1

What is the difference between these two pointers? Both pointers are pointing to an array? Is it because the first pointer is a pointer to the first element of the array, while the other is a pointer to an array of 5 elements? What differences does this make in code?

int arr[5] = {1,2,3,4,5};
int *pointer = arr;
int (*pointer2)[5] = arr;
user737163
  • 431
  • 3
  • 9
  • 1
    You should be getting a warning for the last: `initialization of 'int (*)[5]' from incompatible pointer type 'int *' [-Wincompatible-pointer-types]` – mediocrevegetable1 May 29 '21 at 18:11
  • With `pointer`, the line `int x = pointer[2]` would set `x` to 3. With `pointer2`, the line `int x = pointer2[0][2]` would set `x` to 3. So `pointer2` is not really useful in your example. It would be useful (and wouldn't generate a warning) with an array like `int arr[2][5]` – user3386109 May 29 '21 at 18:12
  • @user3386109 what difference does it provide in the last case? – user737163 May 29 '21 at 18:13
  • The difference is a 1D array versus a 2D array. – user3386109 May 29 '21 at 18:15

4 Answers4

3

Your first declaration

int *pointer = arr;

declares pointer as a pointer to a single integer. In the initialization, arr decays to a pointer to its first element, so it's equivalent to

int *pointer = &arr[0];

The second one

int (*pointer2)[5] = arr;

declares pointer as a pointer to an array of 5 integers. The initialization isn't valid, because arr decays to a pointer to a single integer, not an array. You'd need to add a cast:

int (*pointer2)[5] = (int(*)[5])arr;

or take the address of the array (because the decay to pointer doesn't take place when taking the address of the array):

int (*pointer)[5] = &arr;

The different between the two pointer types becomes apparent when you perform pointer arithmetic, because pointer arithmetic is performed in increments of the size of the type it points to. pointer+1 is a pointer to arr[1], but pointer2[1] would be a pointer to arr[5], which doesn't exist.

Barmar
  • 741,623
  • 53
  • 500
  • 612
2

The second,

int (*pointer2)[5] = arr;

is an error (constraint violation): initialization with wrong pointer type where there is no implicit conversion. It should be = &arr.

Both point to the same place, but have different types. This affects not only type checking, but pointer arithmetic and other things. For example, pointer+1 points to arr[1], but pointer2+1 points "one past the end" of the object arr.

The need for pointer-to-array (rather than just pointer-to-element) types comes up when you work with multi-dimensional arrays. In

int matrix[3][3];

the name matrix alone decays not to a pointer to matrix[0][0], but to a pointer to matrix[0] (an array of 3 ints representing a "row"). This is what makes multi-dimensional array indexing and pointer arithmetic work.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • So what is the difference in initializing a pointer in these two ways? scores[3][5] = ...; int (*pointer)[5] = scores; VS int *pointer = scores; – user737163 May 29 '21 at 18:17
  • @user737163: The latter is invalid for the same reason as the first sentence of my answer. The types do not match. `scores` decays to `int (*)[5]` (pointer to array of 5 `int`s) not `int *`. – R.. GitHub STOP HELPING ICE May 29 '21 at 19:56
2

The most notorious difference, in terms of usability, is regarding pointer arithmetic, i.e.:

pointer++ will make the pointer access the second element in the array whereas pointer2++ will make the pointer access the next block of 5 ints. In your code the behavior of this latter case would be undefined since you only have one block of 5 ints.

A pointer to array of SIZE is useful when handling 2D arrays with SIZE columns as you can easily iterate through array lines with this simplified pointer arithmetic.

dreamcrash
  • 47,137
  • 25
  • 94
  • 117
anastaciu
  • 23,467
  • 7
  • 28
  • 53
0

Basically, variables pointer and pointer2 have different types, however they'll both behave similarly, with the exceptions:

– there will be no array to pointer decay occurring for pointer2 like it does for initial arr, i.e.: e.g.:

#include <stdio.h>

int arr[5] = {1,2,3,4,5};
int *pointer = arr;
int (*pointer2)[5] = &arr;

void func(int *in_arr)
{
   printf("1st: %i, 5th: %i\n", in_arr[0], in_arr[4]);
}

int main(void)
{
    func(pointer);
    func(pointer2); /* generates a warning (in GCC) */
    func(arr);      /* works with no issues*/
}

The warning will be:

ex.c: In function ‘main’:
ex.c:9:14: warning: passing argument 1 of ‘func’ from incompatible pointer type [-Wincompatible-pointer-types]
    9 |         func(pointer2);
      |              ^~~~~~~~
      |              |
      |              int (*)[5]
ex.c:4:24: note: expected ‘int *’ but argument is of type ‘int (*)[5]’
    4 |         void func(int *in_arr)    {
      |                   ~~~~~^~~~~~

– pointer arithmetic will behave differently, pointer+1 will point at second element, while pointer2+1 will point after the array pointer2.

IMO, the (type*)[size] pointers are quite peculiar thing in C. They'll allow, for example, to perform basically a cast to an array type, which is a quite strange thing to do in C – normally, you cannot cast anything to an array type (like.: func( (int [5]) ints_pointer ), however with pointer-type to an array, it's possible to cast to it, so that, e.g.:

// same preamble as in previous example…

void func(int (*in_arr)[5]) {
   printf("1st: %i, 5th: %i\n", ((int *)in_arr)[0], 
        ((int *)in_arr)[4]);
}

int main(void) {
    /* ·•Casts•· to a ·•pointer-to-array•· type to mute warnings */
    func( (int(*)[5]) pointer );
    func( (int(*)[5]) arr );
    /* Generates no warning (in GCC) */
    func(pointer2);
}

works with no issues.

psprint
  • 349
  • 1
  • 10