January 11, 2010 at 06:33 Tags C & C++

Pointers are a great source of confusion in C - newbies have a hard time grasping them. But coupled with arrays, some of the semantics of pointers are complex enough to confound even more seasoned programmers.

Consider this code:

void test ( int ** p) { } int main () { int arr[] = { 30 , 450 , 14 , 5 }; test(&arr); return 0 ; }

Take a moment to ponder - would you expect this code to compile cleanly?

gcc isn't very happy about it, and issues a warning: passing arg 1 of test from incompatible pointer type . C++ has stricter type checking, so let's try running the same code through g++ . As expected, we get an error: cannot convert int (*)[4] to int** for argument 1 to void test(int**)

So what's the problem here? What's wrong with the code above? Well, everything. It's simply invalid, and it makes no sense. Some would think it should work because this works:

void test ( int * p) { } int main () { int arr[] = { 30 , 450 , 14 , 5 }; test(arr); return 0 ; }

But this one works specifically because the C compilers should follow the C standard, which mandates that arrays "decay" into pointers when used as lvalues. Thus, a pointer to the array's first element is actually passed to test and everything works.

But the first code snippet is different. While an array name may decay into a pointer, the address of the array does not decay into a pointer to a pointer. And why should it? What sense does it make to treat an array so?

Pointers to pointers are sometimes passed to modify the pointers (simple pointer arguments don't work here because C passes by value, which would only allow to modify what's pointed, not the pointer itself). Here's some imaginary code (won't compile):

void test ( int ** p) { *p = malloc ... /* retarget '*p' */ } int main () { int arr[] = { 30 , 450 , 14 , 5 }; int * ptr; /* Fine! ** test will retarget ptr, and its new value ** will appear after this call. */ test(&ptr); /* Makes no sense! ** You cannot retarget 'arr', since it's a ** constant label created by the compiler. */ test(&arr); return 0 ; }