Regarding double and triple pointers/double dimension arrays
Asked Answered
F

2

6

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.

Froebel answered 1/6, 2015 at 17:40 Comment(5)
By "not acceptable", what do you mean? Please include the warning or error message.Attune
Are you sure it breaks? ideone.com/KM516t (Note that you are missing a semicolon and are reusing the name aPtr2)Sill
The ideone link I posted compiled it fine for gcc-4.9.2. What compiler flags are you using?Sill
Yeah i know i'm reusing the name, it was just commented out because i had to do the other way around to look at the pointer arithmetic. It does indeed break. this works ideone.com/4ePj4h, but this does not ideone.com/KMG7OS.Froebel
Ahhh, I thought you meant a compile time error! Yes, you'll get a segfault, I'll explain why.Sill
S
1

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
Sill answered 1/6, 2015 at 18:18 Comment(0)
B
2

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).

Bagwell answered 1/6, 2015 at 18:11 Comment(0)
S
1

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
Sill answered 1/6, 2015 at 18:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.