Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to pass char[][] to a function requesting char**?

I am trying to call a function that takes char** as a parameter. Its job is to fill an array of strings (i.e. an array of char*). I know the max length of the strings, and I can pass the max number to fill as another parameter, so I was hoping to stack allocate it like this:

fill_my_strings(char** arr_str, int max_str); // function prototype

char fill_these[max_strings][max_chars_per_string]; // allocating chars
fill_my_strings(fill_these, max_strings); // please fill them!

Of course, I get the "cannot convert char[max_strings][max_chars_per_string] to char**" error.

I know this is some subtle (or not-so-subtle) problem with my understanding of the difference between arrays and pointers. I'm just not sure why it's not possible to pass this block of memory to something wanting a char** and have it fill in my stack-allocated chars. Could somebody please explain if this is possible, or if not, why not?

Is it possible to call a function like this without calling malloc / new?

like image 353
aardvarkk Avatar asked Nov 17 '25 05:11

aardvarkk


2 Answers

The simple answer to your question is no; a two dimensional array is different than a pointer-to pointer type. Arrays decay to pointers to their first element, but pointers actually are that value.

The difference between these types is clear, if you cast both to char*

int x;
char *arr_pp[] = {"foo", "bar", "baz"};
char arr_2d[][4] = {"foo", "bar", "baz"};

char *cp = (char*)arr_pp;
for(x=0; x<3; x++)
     printf("%d ", cp[x]);
printf("\n");

cp = (char*)arr_2d;  
for(x=0; x<3; x++)
     printf("%d ", cp[x]);
printf("\n");

The output (on my computer) is:

-80 -123 4 
102 111 111 

Where the first row is gibberish formed by the fact that I'm printing an address cast into bytes, and the second row is the ascii values of "foo".

In a function taking a char ** the compiler can't know to decay array types, which don't actually contain pointers.

like image 147
Dave Avatar answered Nov 19 '25 19:11

Dave


Suppose you have n pointers to strings of m-1 maximum characters (m characters including the NULL). So, in pure C: sizeof(char[n][m]) will return n*m. sizeof(char**) will return the size of a pointer in your architecture, probably 32 (if x86) or 64 (if x86_64).

char[n][m] actually allocates the n*m byte contiguously. char** allocates a single pointer. This pointer references a memory stripe of *n bytes. Each of these n pointers points to a memory stripe of m characters.

So, considering that sizeof(char) == u, if you declare char a[n][m], when you use a[i][j], the compiler understands *(a + i*m*u + j*u). So, considering that sizeof(char *) == w, if you declare char **a, when you use a[i][j], the compiler understands ((a + i*w) + j*w).

Completely different data management.

The closes thing you could do to handle your special case is to create a char** variable, and populate it with the addresses of your stack allocated matrix.

char **tmp = malloc(max_strings * sizeof(char *));
int i;
for(i = 0; i < max_strings; i++){
    tmp[i] = &(fill_these[i][0]); //you probably can't reference a char[][] with a single index - not confirmed
}
like image 24
Spidey Avatar answered Nov 19 '25 18:11

Spidey