Why can't I access a pointer to pointer for a stack array?
test
is an array, not a pointer, and &test
is a pointer to the array. It is not a pointer to a pointer.
You may have been told that an array is a pointer, but this is incorrect. The name of an array is a name of the entire object—all the elements. It is not a pointer to the first element. In most expressions, an array is automatically converted to a pointer to its first element. That is a convenience that is often useful. But there are three exceptions to this rule:
- The array is the operand of
sizeof
. - The array is the operand of
&
. - The array is a string literal used to initialize an array.
In &test
, the array is the operand of &
, so the automatic conversion does not occur. The result of &test
is a pointer to an array of 256 char
, which has type char (*)[256]
, not char **
.
To get a pointer to a pointer to char
from test
, you would first need to make a pointer to char
. For example:
char *p = test; // Automatic conversion of test to &test[0] occurs.
printchar(&p); // Passes a pointer to a pointer to char.
Another way to think about this is to realize that test
names the entire object—the whole array of 256 char
. It does not name a pointer, so, in &test
, there is no pointer whose address can be taken, so this cannot produce a char **
. In order to create a char **
, you must first have a char *
.
Because test
is not a pointer.
&test
gets you a pointer to the array, of type char (*)[256]
, which is not compatible with char**
(because an array is not a pointer). This results in undefined behavior.
The type of test2
is char *
. So, the type of &test2
will be char **
which is compatible with the type of parameter x
of printchar()
.
The type of test
is char [256]
. So, the type of &test
will be char (*)[256]
which is not compatible with the type of parameter x
of printchar()
.
Let me show you the difference in terms of addresses of test
and test2
.
#include <stdio.h>
#include <stdlib.h>
static void printchar(char **x)
{
printf("x = %p\n", (void*)x);
printf("*x = %p\n", (void*)(*x));
printf("Test: %c\n", (*x)[0]);
}
int main(int argc, char *argv[])
{
char test[256];
char *test2 = malloc(256);
test[0] = 'B';
test2[0] = 'A';
printf ("test2 : %p\n", (void*)test2);
printf ("&test2 : %p\n", (void*)&test2);
printf ("&test2[0] : %p\n", (void*)&test2[0]);
printchar(&test2); // works
printf ("\n");
printf ("test : %p\n", (void*)test);
printf ("&test : %p\n", (void*)&test);
printf ("&test[0] : %p\n", (void*)&test[0]);
// Commenting below statement
//printchar((char **) &test); // crashes because *x in printchar() has an invalid pointer
free(test2);
return 0;
}
Output:
$ ./a.out
test2 : 0x7fe974c02970
&test2 : 0x7ffee82eb9e8
&test2[0] : 0x7fe974c02970
x = 0x7ffee82eb9e8
*x = 0x7fe974c02970
Test: A
test : 0x7ffee82eba00
&test : 0x7ffee82eba00
&test[0] : 0x7ffee82eba00
Point to note here:
The output (memory address) of test2
and &test2[0]
is numerically same and their type is also same which is char *
.
But the test2
and &test2
are different addresses and their type is also different.
The type of test2
is char *
.
The type of &test2
is char **
.
x = &test2
*x = test2
(*x)[0] = test2[0]
The output (memory address) of test
, &test
and &test[0]
is numerically same but their type is different.
The type of test
is char [256]
.
The type of &test
is char (*) [256]
.
The type of &test[0]
is char *
.
As the output shows &test
is same as &test[0]
.
x = &test[0]
*x = test[0] //first element of test array which is 'B'
(*x)[0] = ('B')[0] // Not a valid statement
Hence you are getting segmentation fault.