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;
4
  • 1
    You should be getting a warning for the last: initialization of 'int (*)[5]' from incompatible pointer type 'int *' [-Wincompatible-pointer-types] Commented May 29, 2021 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] Commented May 29, 2021 at 18:12
  • @user3386109 what difference does it provide in the last case? Commented May 29, 2021 at 18:13
  • The difference is a 1D array versus a 2D array. Commented May 29, 2021 at 18:15

4 Answers 4

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, I showed both (with an explanation).
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.

2 Comments

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: 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 ints) not int *.
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.

Comments

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.