Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++: function arg char** is not the same as char*[]

I am using g++. I am using code that had a main(int,char**), renamed so I can call it. I looked at 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.

like image 513
cvsdave Avatar asked Dec 14 '22 02:12

cvsdave


2 Answers

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.

like image 190
Pavel Minaev Avatar answered Dec 24 '22 07:12

Pavel Minaev


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.

like image 35
P Shved Avatar answered Dec 24 '22 08:12

P Shved