views:

313

answers:

2

I am using g++. I am using code that had a main(int,char**), renamed so I can call it. I looked at http://stackoverflow.com/questions/779910/should-i-use-char-argv-or-char-argv-in-c, where char** is said to be equivalent to char* []. This does not appear to be true in c++ function calls. For example:

void f1(char** p){;}

void f2(char* p[]){

   f1(p);

 //...`

}

fails with the compiler complaining "cannot convert char (*)[] to char**..." The references I look to say that arrays are converted to pointers for the call, but this does not seem to be the case as:

void f3(char* [] p);

char caa[16][16];  
f3(caa);

also fails. I had assumed that as long as the levels of indirection were the same (e.g. char*** ptr and char[][][] carray ) the types were interchangeable.

Can someone provide a reference I can review that clarifies these issues?

Thanks.

+11  A: 

This still holds true in C++. If your compiler complains as you describe for your first case, it is non-conformant.

To explain your second case, it is important to understand what actually happens. An expression of array type is implicitly convertible to a corresponding pointer type, i.e.: T[n] -> T*. However, if T itself is an array, this case isn't treated specially, and array-to-pointer decay does not propagate. So T*[n] decays to T**, but T[x][y] will only decay to T[y]*, and no further.

From implementation perspective this makes sense, because decaying further, if allowed, would give T**, which is pointer to pointer; whereas 2D C arrays aren't implemented as jagged arrays (i.e. array of pointers to arrays) - they form a single contiguous memory block. So, there's no T* "inside" the array to take an address of to give you a T**. For the allowed cases, a typical implementation simply takes the address of the array as a whole and converts it to type of pointer to single element (when underlying pointer representation is the same for all types, as is usually the case, this convertion is a no-op at run time).

The normative reference here is ISO C++03, 4.2[conv.array]/1:

An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to an rvalue of type “pointer to T.” The result is a pointer to the first element of the array.

Pavel Minaev
Actually, I was hoping for a URL. I don't really understand what you are saying. Is char** equiv to char* []? It seems to me:char c;char* cp = `char** cpp =
cvsdave
It is equivalent, but _only_ in function declarations, when applied to argument types. Also, `char*[]` is implicitly convertible to `char**`, but `char[][]` is not.
Pavel Minaev
Pavel Minaev
@cvsdave, In particular, compare `*(int(*)[1])0` with `*(int**)0`. The first practically doesn't crash, because dereferencing an array pointer will not read anything from memory - it just passes the address through and only changes the type. Dereferencing the `int**` pointer, however, will read an `int*` from a specific address (null pointer address here, which will likely crash). So even when the "level of indirections" seem to be equal - they *mean* very different things for arrays and for pointers :)
Johannes Schaub - litb
@cvsdave, to complement pavel's nice answer with some experiments on the level of indirections, you could have a look at this answer: http://stackoverflow.com/questions/274865/pointer-question-in-c/274943#274943
Johannes Schaub - litb
A: 
void f2(char* p[]){

the compiler complaining "cannot convert char (*)[] to char**..."

Strange. char(*)[] is a pointer to array of chars, but in your code snippet the function has char *p[] argument, what means array of pointers to char! These types are indeed different (because array elements have different sizes), let alone your code snippet perfectly compiles. You really have misspelled something.

Sherlock Holmes mode: or is there a typedef involved? ;-)

void f1(char** p){;}

typedef char type[];
void f2(type * p){
   f1(p);
}

This really doesn't compile and yields the error you referred to.

Pavel Shved
void f4(char* [16]){;}int main*int argc, char** argv){char caa[16][16];f4(caa);}yields:a.cpp: In function `int main(int, char**)':a.cpp:4: error: cannot convert `char (*)[16]' to `char**' for argument `1' to `void f4(char**)'g++ 3.4.5 run on Redhat 5 and Win XPThis is what puzzles me.
cvsdave
Well, Pavel Minaev has explained above that `char caa[16][16]` during function call is converted to `char (*caa)[16]`. This means, `*caa` denotes the *array* of characters and is equal to `caa`. What you want is converting it to `(char *)caa[16]`, or, differently, `char *caa[16]`, which can't be done due to the reasons I explained in my post.
Pavel Shved