user4709059
user4709059

Reputation: 125

Regarding double and triple pointers/double dimension arrays

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

Answers (2)

mtijanic
mtijanic

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

wcochran
wcochran

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

Related Questions