C - 'char **' differs in levels of indirection from 'char (*)[6]' - c

Can someone please explain to me what's wrong with the following, and more importantly why?
int main( int argc, char *argv[] )
{
char array[] = "array";
char **test;
test = &array;
*test[0] = 'Z';
printf( "%s\n", array );
return 0;
}
EDIT
My example above was based on a function like this that was crashing:
void apple( char **pp )
{
*pp = malloc( 123 );
*pp[0] = 'a'; // technically this is correct but in bad form
*pp[1] = 'b'; // incorrect but no crash
*pp[2] = '\0'; // incorrect and crash
}
As pointed out to me by Vaughn Cato although *pp[0] = 'a'; does not crash it is in bad form. The correct form is the parenthesis
void apple( char **pp )
{
*pp = malloc( 123 );
(*pp)[0] = 'a'; // correct
(*pp)[1] = 'b'; // correct
(*pp)[2] = '\0'; // correct
}
Also as another poster MK pointed out the FAQ covers the difference between arrays and pointers:
http://www.lysator.liu.se/c/c-faq/c-2.html

test = &array
is wrong because test is of type char** and &array is a char(*)[6] and is a different type from char**
An array isn't the same type as char* although C will implicitly convert between an array type and a char* in some contexts, but this isn't one of them. Basically the expectation that char* is the same as the type of an array (e.g: char[6]) is wrong and therefore the expectation that taking the address of an array will result in a char** is also wrong.

This would be the way to do what you seem to be trying to do:
int main( int argc, char *argv[] )
{
char array[] = "array";
char (*test)[6];
test = &array;
(*test)[0] = 'Z';
printf( "%s\n", array );
return 0;
}
test is a pointer to an array, and an array is different from a pointer, even though C makes it easy to use one like the other in my cases.
If you wanted to avoid having to specify a specific sized array, you could use a different approach:
int main( int argc, char *argv[] )
{
char array[] = "array";
char *test;
test = array; // same as test = &array[0];
test[0] = 'Z';
printf( "%s\n", array );
return 0;
}

char **test; is a pointer to a pointer, but if you're going to take the address of an entire array then it needs to be a pointer to entire array i.e char (*test)[6];

Related

What is the meaning of changing char pointer to int pointer

I have the following code from previous exam in c:
int main(int argc, char **argv) {
char s[] = "123";
int* a = (int*) s;
printf(("%x"),*a);
return 0;
}
The output is: 333231
My question is why? how does changing the pointer effect it?
You don't have to declare a separate variable. This would do:
printf(("%x"),(int*)s);
The pointer type dictates how the pointee is interpreted when the pointer is dereferenced.

Reverse String with a pointer to a function, which executes the String reverse

I would like to reverse a String with an pointer to a function, which executes the String reverse.
I have the feeling that I did not grasp the concept of using pointer to variables or functions correctly, so I would be very thankful if someone could expain me, where I am thinking wrong here:
1) Define a pointer to a function:
char *strrev(char *str)
{
char *p1, *p2;
if (! str || ! *str)
return str;
for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
{
*p1 ^= *p2;
*p2 ^= *p1;
*p1 ^= *p2;
}
return str;
}
2) Now in my main I define a pointer, which matches the function I defined above:
int main(void) {
char (*functPtr)(char);
functPtr = &strrev;
3) Now I define the String, which I want to reverse, define a new pointer and let the pointer point to the address space of the String.
char str[50] = "Hello, World";
char *pointer[50];
pointer[50] = &str[50];
4) Lastly I define a new String and write the result of the function, which call through the pointer, which points to the pointer to the function.
char t[50] = (*functPtr)(pointer[50]);
printf("%s\n", str);
return(0);
}
Unfortunaly I get all kinds of error message such as:
Ü1.c:29:10: error: array initializer must be an initializer list or string literal
char t[50] = (*functPtr)(pointer[50]);
^
Ü1.c:27:5: warning: array index 50 is past the end of the array (which contains 50 elements) [-Warray-bounds]
pointer[50] = &str[50];
^ ~~
Ü1.c:26:5: note: array 'pointer' declared here
char *pointer[50];
^
Ü1.c:29:30: warning: array index 50 is past the end of the array (which contains 50 elements) [-Warray-bounds]
char t[50] = (*functPtr)(pointer[50]);
^ ~~
Ü1.c:26:5: note: array 'pointer' declared here
char *pointer[50];
^
2 warnings and 1 error generated.
1) Define a pointer to a function:
No, you did not define a pointer to function. You defined a function with the name strrev.
2) Now in my main I define a pointer, which matches the function I
defined above:
int main(void) {
char *(*functPtr)(char *);
functPtr = &strrev;
Yes, you defined a pointer to function and initialized it with the address of the function strrev. As function designators used in expressions are implicitly converted to pointers to function then you could write
int main(void) {
char *(*functPtr)(char *);
functPtr = strrev;
3) Now I define the String, which I want to reverse, define a new
pointer and let the pointer point to the address space of the String.
char str[50] = "Hello, World";
char *pointer[50];
pointer[50] = &str[50];
Except the definition of the character array that contains a string all other records do not make any sense. For starters the function strrev reverses a string in place. It does not create a reversed copy of the passed to it string.
If you want to declare a pointer that will get the address of the reversed string returned by the function that equal to the address of the original string then you could just write
char *pointer = functPtr( str );
4) Lastly I define a new String and write the result of the function,
which call through the pointer, which points to the pointer to the
function.
char t[50] = (*functPtr)(pointer[50]);
printf("%s\n", str);
You already defined a pointer that will get the value returned from the function. So there is no sense to declare one more array. Moreover arrays do not have the assignment operator. And the function reversed the original string in place. Why are you going to create one more array with the duplicate copy of the original reversed string?! This entirely does not make a sense.
Your program can look the following way
#include <stdio.h>
#include <string.h>
char * strrev( char *s )
{
size_t n = strlen( s );
if ( n )
{
for ( char *first = s, *last = s + n; first < --last; ++first )
{
char c = *first;
*first = *last;
*last = c;
}
}
return s;
}
int main(void)
{
char * ( *fp )( char * ) = strrev;
char s[] = "Hello, World";
puts( s );
puts( fp( s ) );
return 0;
}
The program output is
Hello, World
dlroW ,olleH
If you initially wanted that the function would not reverse the original string but make a reversed copy of the original string then in this case indeed there is a sense to define one additional character array that will get the reversed copy of the original string.
In this case the program can look like.
#include <stdio.h>
#include <string.h>
char *reverse_copy( char *s1, const char *s2 )
{
*( s1 += strlen( s2 ) ) = '\0';
while (*s2)
{
*--s1 = *s2++;
}
return s1;
}
int main(void)
{
char * ( *fp )( char *, const char * ) = reverse_copy;
char s[] = "Hello, World";
char t[sizeof( s )];
puts( s );
puts( fp( t, s ) );
return 0;
}
The program output is
Hello, World
dlroW ,olleH
Now the original character array s was not changed while the array t got the reversed copy of the original string stored in the array s.
I summarize my comments in this answer, as it gives more space for details of the comments.
char (*functPtr)(char); should be char *(*functPtr)(char *); as it takes a pointer to a char, not a char. Likewise it returns a pointer.
char *pointer[50]; would be an array of 50 pointers, You want to say "a pointer to an array of 50 chars". In C we don't say that. We just say "a pointer to a char" and don't say how many. So char *pointer; would be enough.
char t[50] = (*functPtr)(pointer[50]); is not correct in C.
You want to assign the result of funcPtr to the array t. But here you mix initialization with assignment.
char t[50]; declares an array of 50 chars. You can initialize it by giving it a value, for example char t[50] = "Hello World"; which will have the compiler copy "Hello World" to the array.
But you try to assign the function pointer to the array. You probably intend to put the result of the function into the array.
Note also that you cannot "assign" an array to another array. You can only copy it.
So the correct code would be:
char *(*functPtr)(char *);
functPtr = &strrev;
char str[50] = "Hello, World";
char t[50];
char *s= funcPtr(str); // call the function and save the returned pointer
strcpy(t, s); // now copy the result to your array.
printf("%s\n", t); // and print it
Note: char str[50] = "Hello, World"; is correct and, just so you'll know, char *str = "Hello, World"; is wrong. Why? Because the second str will point to read-only memory (a "string literal") and any attempt to modify it would abort the program. But here you did it right.

Assigning returned cstring to variable

I'm writing a function that reverses a cstring not in place but returns the reversed cstring. What exactly should the return type be?
#include <stdio.h>
#include <string.h>
const char* reverStr(const char *str)
{
char revStr[strlen(str)];
int i;
for(i = strlen(str)-1; i >= 0; i--)
revStr[strlen(str)-1-i] = str[i];
printf("returned value should be %s\n", revStr);
return revStr;
}
int main()
{
char aStr[] = "hello";
char aStr2[] = "goodbye";
printf("%s %s", aStr, aStr2);
char* tmp = reverStr(aStr);//tmp now has garbage
printf("\n%s", tmp);
printf(" %s", aStr);
return 0;
}
Gives
warning: function returns address of local variable [enabled by default]|
warning: initialization discards 'const' qualifier from pointer target type [enabled by default]|
I tried changing char* tmp to char tmp[] but it wouldn't compile. It confuses me when I should use an array and when I should use a pointer.
revStr is an array and ceases to exist after reverStr function exits. For more please read:
Where is the memory allocated when I create this array? (C)
const char* reverStr(const char *str)
{
char revStr[strlen(str)];
return revStr; /* Problem - revStr is a local variable trying to access this address from another function will be erroneous*/
}
const char* reverStr(const char *str)
{
const char * revStr = str;
return revStr; //ok
}
A modifiable l-value cannot have an array type. An l-value is an expression which can come on the left side of an assignment. You use an array when you want to declare lots of variables of the same type and you can index it easily since its layout will be in a sense contiguous.
You use pointers when you want to keep changing the values of the address where you variable points to.
You can do this:
char * p = "test";
p = "new";
But you cannot do this:
char p[] = "test";
char *p1 ="test1";
p = p1; //error
Because their (arrays and pointers) types are not the same and the array p is a non-modifiable l-value.
Here is your fixed code. I tried to make less modifications.
char revStr[strlen(str)]; allocates a local variable(an array) and when you are out of the scope of the reverStr function, its memory is released, which will lead any further usage of its pointer to be UB(segfault in most cases).
A correct way is to allocate the string on the heap and return its pointer like this
char* x = (char*)malloc(strlen(str));
...
return x;
This requires user to be responsible to free the memory. Or you could pass another parameter to your function for the result string.
I think you should use malloc to allocate a new string.
const char* reverStr(const char *str)
{
char *revStr;//using pointer
int i;
revStr = (char*)malloc(strlen(str));//dynamic allocation
for(i = strlen(str)-1; i >= 0; i--)
revStr[strlen(str)-1-i] = str[i];
printf("returned value should be %s\n", revStr);
return revStr;
}
An array is a pointer point to the head of continuous memory.
for example:
int a[] = {1,2,3};
The address in memory maybe:
--1000
|1|
--1004
|2|
--1008
|3|
--1012
1000, 1004, and 1012 are the value of address in memory.
Thus, the value of array a should be 1000.
printf("%d",a);// Yes, you can do it and you may get the value of 1000.
Also, you can use the following code.
int a[] = {1,2,3};
int *b;
b= a;
printf("%d",b[1]);// you will get "2".
You can consider that pointer is a set and array is in the set.
Therefore, you can NOT do this;
int a[] = {1,2,3};
int c = 0;
int *b = &c;
a = b;//error

Swap char with table pointers in C

I'm trying to swap two char with two table pointers.
Can someone explain to me what's wrong in my code?
The terminal says char** is expected but I don't know what to do, so I think I don't really understand how pointers work for tables.
void echangeM2(char **ptab1, char **ptab2){
char *tmp = *ptab1;
*ptab1 = *ptab2;
*ptab2 = *tmp;
printf("%s\t %s",*ptab1,*ptab2);
return;
}
int main(void) {
char tab1[25];
char tab2[25];
char *adtab1;
char *adtab2;
*adtab1 = &tab1;
*adtab2=&tab2;
printf("type two words");
scanf("%s %s",tab1,tab2);
echangeM2(adtab1,adtab2);
return 0;
}
The following code should work for you:
#include <stdio.h>
void exchangeM2(char* *ptab1, char* *ptab2) { // accepts pointer to char*
char* tmp = *ptab1; // ptab1's "pointed to" is assigned to tmp
*ptab1 = *ptab2; // move ptab2's "pointed to" to ptab1
*ptab2 = tmp; // now move tmp to ptab2
printf("%s\t %s",*ptab1,*ptab2);
}
int main(void) {
char tab1[25];
char tab2[25];
char* adtab1;
char* adtab2;
adtab1 = tab1; // array name itself can be used as pointer
adtab2 = tab2;
printf("type two words");
scanf("%s %s",tab1,tab2);
exchangeM2(&adtab1, &adtab2); // pass the address of the pointers to the function
}
echangeM2(&adtab1,&adtab2);
This should fix the compile errors. You are passing char* pointers to a function that expects a char ** pointer
Edit: Actually looks like you want something like
char **adtab1;
char **adtab2;
adtab1 = &tab1;
adtab2=&tab2;
...
echangeM2(adtab1,adtab2);

How to Return an Array of Strings in C?

For example, I have in the main file
1) char ** array[NUMBER];
2) array = build_array();
and in an imported file
char ** build_array()
{
char ** array[NUMBER];
strings[0] = "A";
strings[1] = "B";
return (char *) strings;
}
However, at line 2 in the main file, I get the error: "incompatible types when assigning to type 'char **[(unsighed int)NUMBER]' from type 'char **'
What am I doing wrong? Any suggestions or advice would be appreciated. Thank you in advance.
There seem to be some confusion about what a string is in C. In C, a null terminated sequence of chars is considered a string. It is usually represented by char*.
I just want to call the build_array() function and return the array of strings
You pretty much can't return an array, neither a pointer to a local array. You could however pass the array to build_array as an argument, as well as its size, and fill that instead.
void build_array( char* strings[], size_t size )
{
// make sure size >= 2 here, based on your actual logic
strings[0] = "A";
strings[1] = "B";
}
...later called as:...
char *array[NUMBER];
build_array(array, NUMBER);
The alternatives are to return a pointer to a global or static allocated array, which would make your function non-reentrant. You probably don't care about this now, but is bad practice so I would recommend you avoid going that route.
As littleadv pointed out, there are several problems with your code:
Mismatch between char ** and char **[ ]
Returning a pointer to a local variable
Etc.
This example might help:
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#define NUMBER 2
#define MAX_STRING 80
char **
build_array ()
{
int i = 0;
char **array = malloc (sizeof (char *) * NUMBER);
if (!array)
return NULL;
for (i = 0; i < NUMBER; i++) {
array[i] = malloc (MAX_STRING + 1);
if (!array[i]) {
free (array);
return NULL;
}
}
strncpy (array[0], "ABC", MAX_STRING);
strncpy (array[1], "123", MAX_STRING);
return array;
}
int
main (int argc, char *argv[])
{
char **my_array = build_array ();
if (!my_array) {
printf ("ERROR: Unable to allocate my_array!\n");
return 1;
}
else {
printf ("my_array[0]=%s, my_array[1]=%s.\n",
my_array[0], my_array[1]);
}
return 0;
}
Your return type is char**, while you're assigning it to char**[], that's incompatible.
Other than that you should post the actual code that you have problem with, the code you posted doesn't compile and doesn't make much sense.
In order to fix your code, the function should be returning char **[NUMBER]. Note also, that you're casting the return value to char* instead of char** that you declared (or char **[NUMBER] that it should be, and in fact - is).
Oh, and returning a pointer to a local variable, as you do in your case, is a perfect recipe for crashes and undefined behavior.
What you probably meant was:
char *array[NUMBER];
int ret = build_array(array, NUMBER);
// do something with return value or ignore it
and in an imported file
int build_array(char **arr, int size)
{
// check that the size is large enough, and that the
// arr pointer is not null, use the return value to
// signal errors
arr[0] = "A";
arr[1] = "B";
return 0; // asume 0 is OK, use enums or defines for that
}

Resources