Reputation: 125
So, i was playing with C pointers and pointer arithmetic since i'm not entirely comfortable with them. I came up with this code.
char* a[5] = { "Hi", "My", "Name", "Is" , "Dennis"};
char** aPtr = a; // This is acceptable because 'a' is double pointer
char*** aPtr2 = &aPtr; // This is also acceptable because they are triple pointers
//char ***aPtr2 = &a // This is not acceptable according to gcc 4.8.3, why ?
//This is the rest of the code, the side notes are only for checking
printf("%s\n",a[0]); //Prints Hi
printf("%s\n",a[1]); //Prints My
printf("%s\n",a[2]); //Prints Name
printf("%s\n",a[3]); //Prints Is
printf("%s\n",a[4]); //Prints Dennis
printf("%s\n",*(a+0)); //Prints Hi
printf("%s\n",*(a+1)); //Prints My
printf("%s\n",*(a+2)); //Prints Name
printf("%s\n",*(a+3)); //Prints Is
printf("%s\n",*(a+4)); //Prints Dennis
printf("%s\n",*(*(aPtr2) +0)); //Prints Hi
printf("%s\n",*(*(aPtr2) +1)); //Prints My // ap = a, *ap = *a, *(ap)+1 = *a+1 ?
printf("%s\n",*(*(aPtr2) +2)); //Prints Name
printf("%s\n",*(*(aPtr2) +3)); //Prints Is
printf("%s\n",*(*(aPtr2) +4)); //Prints Dennis
char*** aPtr2 = &a
is not acceptable according to gcc 4.8.3, why?
Sorry forgot to add compiler warning:
warning: initialization from incompatible pointer type [enabled by default]
It maybe unclear what I'm trying to say, so I had to add this links:
Notice the commented out lines.
Upvotes: 6
Views: 170
Reputation: 2902
This comes from the way C treats arrays and addresses:
int a[5];
a
is of the type int * const
, true, meaning you can use it where a pointer is expected. However, on the stack the space for the pointer isn't allocated, only the space for the five ints. Meaning a
is the same as &a[0]
. This is all expected, but here comes the weird part:
a
is the same as &a
. This is because the pointer isn't stored anywhere, you can't get it's address. But instead of failing the compile, the C standard just says that they are the same, so some arithmetic will work.
However, since you are doing char ***aPtr2 = &a;
, you are effectively doing char ***aPtr2 = a;
, which is why you get a segfault. It is only a double pointer, not a triple one.
You can inspect all the values in the debugger to see it more clearly, or run a program such as:
#include <stdio.h>
int main(void)
{
char *a[5] = { "Hi", "My", "Name", "Is" , "Dennis"};
char **aPtr = a;
char ***aPtr2 = &aPtr;
char ***aPtr3 = &a;
printf("%p %c\n", a, *a);
printf("%p %p %c\n", aPtr, *aPtr, **aPtr);
printf("%p %p %p %c\n", aPtr2, *aPtr2, **aPtr2, ***aPtr2);
printf("%p %p %c\n", aPtr3, *aPtr3, **aPtr3);
return 0;
}
which produces the output:
0xfff65578 H
0xfff65578 0x8048648 H
0xfff65574 0xfff65578 0x8048648 H
0xfff65578 0x8048648 H
EDIT: Another interesting thing is the function pointers are treated in the same fashion. &func
is the same as func
.
int add(int a, int b) { return a + b; }
typedef int (*PFUNC)(int, int);
PFUNC p1 = add;
PFUNC p2 = &add;
if (p1 == p2)
printf("Huh. %d, %d\n", (*p1)(1,2), p2(3, 4)); // the dereference is also optional
Upvotes: 1
Reputation: 10896
a
is the address of a buffer of 5 ptrs and is immutable (i.e. its a fixed ptr). If you allowed
char ***aPtr2 = &a;
then
*aPtr2 = &a[3];
would actually modify the address a
(which is verboten).
Upvotes: 2