Pointers to arrays in C
January 11th, 2010 at 6:33 amPointers 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;
}
Pointers to arrays
Note that the original code could be modified a little to make it work:
void test(int (*p)[4])
{
(*p)[2] = 10;
}
int main()
{
int arr[] = {30, 450, 14, 5};
test(&arr);
printf("%d\n", arr[2]);
return 0;
}
What is that weird type test accepts now? Say hello to a "pointer to array", one of the useless features of C. This is what the C FAQ has to say about it:
2.12: How do I declare a pointer to an array?
Usually, you don’t want to. When people speak casually of a pointer to an array, they usually mean a pointer to its first element.
Truly, I can’t imagine why one would use a pointer to an array in real life. If you do a web search on the topic, most of what you find is people mistakingly calling the parameter of foo(int* p) "a pointer to array", which of course it isn’t. It looks to me like the whole concept is just an artifact of C’s declaration syntax.
While the test function from the previous snippet compiles and works, it isn’t of much use, since it’s much clearer to write:
void test(int* p)
{
p[2] = 10;
}
...
...
/* then call */
test(arr);
The main use of pointers as function arguments is to either avoid passing whole structures by value, or to modify the object pointed by the pointers. Both are irrelevant needs for pointers to array. Here’s a clarifying snippet:
int joe[] = {1, 2, 3, 4};
void test(int (*p)[4])
{
/* Fine: assign to an element through the
** pointer.
*/
(*p)[2] = 10;
/* Works, but won't be reflected in the
** caller since p was passed by value.
*/
p = &joe;
/* Error: arrays can't be assigned.
*/
*p = joe;
}
Arrays are not passed by value anyway, so a pointer to an array is useless for this purpose. Neither can arrays be modified, so that kills the second reason.
Related posts:

January 11th, 2010 at 20:52
I would have written :
int* arr = {30, 450, 14, 5};
instead of :
int arr[] = {30, 450, 14, 5};
And I suppose I woulnd’t have even see a problem.
Is there a problem with that ?
January 11th, 2010 at 21:12
@sage: this won’t compile, it’s invalid to initialize a pointer this way
January 11th, 2010 at 23:35
Hi Eli,
I’ve only ever seen pointers to pointers (i.e. **p) used with “ragged arrays” (and that is in my C manual!) – what other “real world” scenarios might one use these in?
Thanks for you column!
–Robin
January 12th, 2010 at 02:18
@Robin: Another place that I’ve seen pointers to pointers, other than ragged arrays, is an array of linked lists…. but in a way, that’s still a ragged array. Humph.
January 12th, 2010 at 03:34
A pointer to an array might also be part of an array of pointers to arrays. Passing in a pointer to an array and a number of such pointers would let you walk the list of arrays via pointer arithmetic on the pointer you pass in. You could use an array of pointers for that, but C already provides the functionality to let you do pointer arithmetic in place of array indexing, so it would be odd to require it for arrays of pointers to other arrays, but not those other arrays themselves.
Also, it seems to me that preventing the passing of pointers to arrays would mean that passing pointers to pointers to arrays (so you could modify which array the pointer you passed in was pointing to – something of a more obviously useful feature) either impossible or more complicated to implement.
January 12th, 2010 at 04:38
This is a common question by many beginning C programmers and I only wish that I could of seen this when I was learning C
January 12th, 2010 at 18:23
@Robin, pointers to pointers are useful in a variety of situations. Some of the most common are: 2D arrays or matrices, and to modify pointers in functions (sometimes that’s useful – i.e. when a function allocates memory to a pointer the caller provides it with). Also see the standard function
strtodfor a use.