1

I stumbled upon "pointer to the entire array" and wrote a test program to clear some things out:

#include <stdio.h>

int main(){

    int x[5] = {1, 2, 3, 4, 5};

    int  *a     =  x;   // points to the 1st array element
    int (*b)[5] = &x;   // points to the 1st addres of the stream of 5 int elements
    int (*c)[5] = x;    // points to the 1st addres of the stream of 5 int elements

    printf("%p\n%p\n%p\n\n",
        (void *)a,
        (void *)b,
        (void *)c
    );

    ++a;
    ++b;
    ++c;

    printf("%p\n%p\n%p\n\n",
        (void *)a,
        (void *)b,
        (void *)c
    );

    return 0;
}

This outputs:

0x7ffed0c20690
0x7ffed0c20690
0x7ffed0c20690

0x7ffed0c20694
0x7ffed0c206a4
0x7ffed0c206a4

To me it looks like lines:

    int (*b)[5] = &x;
    int (*c)[5] = x;

achieve exact same result, because:

  • they assign the same addres (in case of *b it is the address of entire array and in case of *c it is the address of the first array member but those two overlap) and

  • assign same pointer size of 5 · int for *b and *c which leads to the exactly same pointer arithmetics when I increment the values.


Q1: Are there any hidden differences between definitions of *b and *c that I am missing?

Q2: Does pointer arithmetics only depends on the size of the pointer?


After you pointed I noticed that I do get an error:

main.c:9:16: warning: initialization of ‘int (*)[5]’ from incompatible pointer type ‘int *’ [-Wincompatible-pointer-types]
  int (*c)[5] = x; // points to the 1st array element
71GA
  • 1,132
  • 6
  • 36
  • 69
  • 1
    `int (*c)[5] = x;` *should* give you a phat warning. Example from msvc14.0 : "warning C4047: 'initializing': 'int (*)[5]' differs in levels of indirection from 'int * '" – WhozCraig Apr 27 '20 at 10:52
  • I get no warning and my `-Wpedantic` flag is on at compile time. – 71GA Apr 27 '20 at 10:54
  • `-Wall -Wextra -Werror` should (always) be included on your chain of command. – WhozCraig Apr 27 '20 at 10:54
  • @WhozCraig It looks like I was not paying enough attention. I really got a warning. Look at the question. – 71GA Apr 27 '20 at 10:57
  • 1
    [How do I use arrays in C++?](https://stackoverflow.com/q/4810664/430766) and its answers are probably highly relevant. – bitmask Apr 27 '20 at 11:05

1 Answers1

3

Q1: Are there any hidden differences between definitions of *b and *c that I am missing?

Pointer arithmetic on these two pointers will remain the same. Because internally array decays into the pointer to the first element in it, i.e. arr[n] will be converted to an expression of type "pointer to arr", and its value will be the address of the first element in the array.

Q2: Does pointer arithmetics only depends on the size of the pointer?

No, it depends on the size of the underlying type pointed to. Even in your provided sample input ++a and ++b are yielding different results. Because ++a offsets pointer by sizeof(int) which is 4. But in case of ++b your pointer is incremented by size of 5 * sizeof(int) by 20 (decimal)

Inian
  • 80,270
  • 14
  • 142
  • 161
  • Do you have any idea on how to avoid the warning that I added at the end? Would it be possible to typecast right hand side of the statement `int (*c)[5] = x;`? I know how to the right hand side to seldomly used types e.g. `(int *) x` which yields the same result. But how would I typecast to a 5 · `int`? I tried `(int *)x([5])` which is not working... – 71GA Apr 27 '20 at 11:10
  • Why do you want it to be suppressed? It is perfectly valid because of the different pointer types @71GA It is a perfect legit warning and can be avoided if use the right pointer types – Inian Apr 27 '20 at 11:24
  • It is not my intention to surpress the message but to find a way to make the pointers equal so that program is valid and message goes away. So... is it possible to reach equality in this statement *(type-wise)* `int (*c)[5] = x;` withouth using the ampersand `int (*c)[5] = &x;` or is this the only way? Could I use typecasting on the right hand side to solve this? I know how to typecast e.g. `(int *) x`, `(void *) x`... but I don't know how to typecast a pointer to be of lenght 5 · `int`. Could I use something like `(int[5] *) x`, `(int *) x[5]`, `(int *) x ([5])` or anything similar? – 71GA Apr 27 '20 at 14:52
  • 1
    You can't achieve type-wise equality, do understand that they both point to _different_ types underneath. I'm afraid you'll have to live with it. You can't have a `(*b)[5]` to point to an `int *` at all – Inian Apr 27 '20 at 14:59
  • Okay. This is a good information. One more thing. Why did then my arithmetic work? Did compiler forcibly make both sides of the equality the same size? – 71GA Apr 27 '20 at 15:03
  • What size are you referring to here? There is "no" same size here. You created two pointers each with different types pointing underneath. Their only common trait is that the base address to both these pointers is the same. – Inian Apr 27 '20 at 15:15
  • I meant the size that is used in pointer arithmetics. For example if I have an integer pointer `int *a`, and I use `++a` address is increased by `0x4`. But if I have `int (*b)[5]` and I do `++b` size is increased for `0x14`. So *"size for pointer arithmetic"* is clearly different. This is what I meant. – 71GA Apr 27 '20 at 17:42