2

I have a simple C code:

int main()
{
    int test[10] = {1,2,3,4,5,6,7,8,9,10};
    int **ptr = &test;

    printf("%d\n", (*ptr)[0]);

    return 0;
}

As soon as it reaches the printf line, it crashes:

Process returned -1073741819 (0xC0000005)   execution time : 0.865 s

When compiling the code on Ubuntu, it gives me the warning:

test.c:8:17: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
     int **ptr = &test;

However, if I instead dynamically allocate the memory on the heap, the code works:

int main()
{
    int *test = malloc(sizeof(int)*10);
    for (int i = 0; i < 10; i++) {
        test[i]=i;
    }
    int **ptr = &test;

    printf("%d\n", (*ptr)[1]);

    return 0;
}

Please explain to me, why the code works when the array is on the heap, but not on the stack?

Victor2748
  • 4,149
  • 13
  • 52
  • 89
  • `main.c:5:11: warning: incompatible pointer types initializing 'int **' with an expression of type 'int (*)[10]' [-Wincompatible-pointer-types] int **ptr = &test;` – ggorlen Jan 26 '20 at 23:42
  • `[cquery] incompatible pointer types initializing 'int **' with an expression of type 'int (*)[10]' [-Wincompatible-pointer-types]`, no need to compile... – anastaciu Jan 26 '20 at 23:45
  • `int *ptr = test;` and `printf("%d\n", ptr[0]);` seems like a saner/the intended use case. – ggorlen Jan 26 '20 at 23:46
  • 1
    FYI, `int **ptr = &test;` is not valid C. With `-pedantic-errors` GCC gives a error here. – HolyBlackCat Jan 26 '20 at 23:53

1 Answers1

2

In order to get your ptr variable to be the "address of an array of integers" you actually need a rather more subtle (and arcane) declaration.

This will work:

int (*ptr)[10] = &test;

as it declares that, when dereferenced (i.e. when you then actually use the expression *ptr), it will be an array (of 10 elements).

In some ways, the structure of the declaration is a bit like that for pointers-to-functions.

EDIT: In your second case, test is a plain old pointer (with a value assigned to it by the malloc call); as such, it is itself a variable whose address can be taken (as your int **ptr = &test; line does - correctly).

However, in the first case ('fixed' array), test refers to a block of memory; in many ways, this can be used as a pointer to the first element (like it will be in a function call, for example). But what value can the compiler possibly assign to the "address of the address of the first element?" This is what fails in the attempted assignment using &test in this case.

But, you would be entitled to ask, according to the previous paragraph, how does the compiler determine a value for &test (to assign to ptr) with the code given in this answer? Well, if you add the following line to your program:

printf("%p %p\n", test, &test);

you will see that test and &test (you can change &test for ptr - the output will be the same) have exactly the same value! Thus, using this 'arcane' declaration, you give the compiler enough information to know what to do with the "array pointer" - basically, it sort of 'ignores' (or bypasses) the first level of dereferencing, ending up with the address of the array's first element (as is).

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83