2

In some c code I inherited, I have seen the following

int (*b)[] = (int(*)[])a;

What is int(*)[] and how is this different than int**?

Adam
  • 562
  • 2
  • 15
  • 9
    [www.cdecl.org](https://cdecl.org/?q=int+%28*b%29%5B%5D) – WhozCraig Aug 18 '22 at 05:05
  • 1
    1) `int (*b)[]` [declares](https://learn.microsoft.com/en-us/cpp/c-language/c-declarations-and-definitions?view=msvc-170) "b" as a pointer to an array of int. 2) `(int(*)[])` [casts](https://www.tutorialspoint.com/cprogramming/c_type_casting.htm) "a" to a point to an array of int. – paulsm4 Aug 18 '22 at 05:12

2 Answers2

8

As per The ``Clockwise/Spiral Rule'',

int(*)[] is a pointer to an array of int.

int(*)[]       int[]
+---------+    +---------+
|      ------->|         |
+---------+    +---------+
               :         :

int** is a pointer to a pointer to an int.

int**          int*           int
+---------+    +---------+    +---------+
|      ------->|      ------->|         |
+---------+    +---------+    +---------+
               :?        :?   :?        :?

As you can see, int(*)[] is closer to int* than to int**.

int*           int
+---------+    +---------+
|      ------->|         |
+---------+    +---------+
               :?        :?
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Understood, but in use, if I had `int **c = (int**)a;`, would (*b)[1] == (*c)[1] or does this have no common meaning? – Adam Aug 18 '22 at 05:23
  • That would make no sense. And it would be undefined behaviour. You'd be comparing the int* after the int* at *c with the int after the int at *b. You might not even be comparing the same locations. (`&(*b)[1])` is commonly different than `&((*c)[1])`.) – ikegami Aug 18 '22 at 05:32
1

All of these have distinctively different meanings:

  • int* = pointer to int
  • int[] = array of int, with incomplete type since the size is missing.
  • int** = pointer to pointer to int.
  • int(*)[] = pointer to (incomplete) array of int

Notably an int**, pointer to pointer to int, cannot be assigned to point at an array, nor to an array of arrays. It has nothing to do with arrays! With one special exception: it can be assigned to point at the first element in an array of int*, that is an array of type int* arr[]. We may then write int** ptr = arr; in that special case and only then.

Most of the misconception regarding int** originates from the misconception that int** together with malloc could be used to allocate a 2D array, which was never the case, see Correctly allocating multi-dimensional arrays.

Regarding int(*)[] it's a handy type in some cases, since an array with no size (incomplete type) is compatible with an array of fixed size (through a special rule called "composite type"). So we can use a int(*)[] to point at any int array type no matter size. Or use it to create a macro to check if something is an array: #define IS_INT_ARRAY(x) _Generic(&(x), int(*)[]: puts(#x " is an int array"))

Lundin
  • 195,001
  • 40
  • 254
  • 396