简体   繁体   中英

How does a pointer to the constant pointer of the first element of an array work?

I wanted to test if I could change the constant pointer that points to the first element of an array in C. While testing I got some strange output that I don't understand:

//Constant pointer to pointer to constant value
void test(int const * * const a) {
    //printf("%d", **a); //Program crashes (2)
    (*a)++;
}

int main()
{
    int a[5] = { 1,2,3,4,5 }; 
    test(&a);
    printf("%d", *a); //Prints 5 as output (1)

    return 0;
}

I expected the compiler to give an error when I try to compile (*a)++ but instead I can run the code, but when I try to print the element I get a strange value (1).

Then I wanted to print out the value (2) of the first element of the array. When I tried this, the program crashes.

The program crashes at the printf because test assumes that when it dereferences a the resulting object is a pointer. If it were one and contained a valid address, the second dereferencing would yield an int object. Alas, a contains the address of the array, which is numerically the address of its first element. The 4 or 8 bytes there are considered an address (because test thinks that *a is a pointer) and the code then tries to access the memory at address 1 in order to print the int value assumed at that address. The address is invalid though, so the program crashes.

Now that we have established that the program considers the data at the beginning of the array a pointer to int, we know what (*a)++ does: it increments the value there by sizeof(int) so that the "pointer" point to the next int "element". I guess an int on your machine is 4 bytes long because 1+4=5, which is printed.

By doing &a you are making a pointer to an array ( int (*)[] ).

Then when this pointer to array is passed to the test function, it's converted to a pointer to a pointer( int ** );

Then (*a)++; is UB.

1. So why 5?

On modern implementation of C like GCC, pointer to a array has the same numerical value as the beginning of the array, so is the address value when the array decays to a pointer: they all are the beginning address of the array.

So, in test , int **a points to the beginning of the array, (*a)++ deferences the pointer as int * and increment the pointer by 1 int element, which is usually implemented as adding the sizeof(int) to the numerical value of the pointer.

Then, 1+sizeof(int) gives you 5.

2. Why it crashed in the second case?

Assuming you are using a 32bit x86 machine, or some machine whose pointer type has the same size as int type, then *a equal to 1 . Then further dereferencing the pointer at a memory address at 1 usually gives you a segfault.

This code is illegal in C, you should get a compiler diagnostic. (If not, turn up your warning level). The results of running any executable produced are meaningless.

The code is illegal because int (*)[5] does not implicitly convert to int const ** .

the constant pointer that points to the first element of an array in C

There is no such thing. You misunderstand what arrays are. Arrays are a series of contiguous elements. int a[5] is like int a; except that there are 5 ints instead of 1 .

int a; and int a[1]; cause identical memory layout. The only difference is the syntax used to access that memory.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM