6

I recently came across the following:

int ( *array )[10] = malloc(...);

Based on my understanding of C's syntax and grammar, this looks like nonsense. It looks like an array is being created (and initialized) with the value of a dereferenced pointer as its identifier.

I understand the idea of pointers to arrays and assigning them blocks on the heap with malloc(), in general, at least. For instance, this makes sense:

int *array = malloc(sizeof (int*) * 10);

...but, the first example looks like gibberish that shouldn't compile. Obviously, I'm missing something.

I feel like I saw whatever this is back when I was learning C, but Googling isn't helping to refresh my understanding. Searches with the terms "pointer", "dereferencing", and "initialization" obviously give results polluted with information on how one keeps track of dereferencing, etc. I'm hoping a human can help me.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
CircleSquared
  • 379
  • 2
  • 11
  • 3
    Wasn't my example clear? :-( You could have told me and I would try to explain it further. – 2501 May 27 '16 at 13:06
  • 3
    It looks weird, but `int (*foo)[10]` declares `foo` as a pointer to an array of 10 `int`s. Remove `()` and `int *foo[10]` declares foo as an array of 10 `pointers to int`s. – Brett Hale May 27 '16 at 13:13
  • This question sounds almost the same like asking, why is `int[]` and `int[][]` (by the way I'm not saying that `int arr[][]` are the same as `(*arr)[]` ) allowed. – Michi May 27 '16 at 13:22
  • The link in this answer points to a guide on how to read C type declarations. http://stackoverflow.com/a/35549769/646887 – Klas Lindbäck May 27 '16 at 13:23
  • @CircleSquared Please take a look [at this Demo](http://ideone.com/fUiQv1) and this [Demo](http://ideone.com/LN38l4) it will help – Michi May 27 '16 at 13:28
  • 2
    I believe [Freaky way of allocating two-dimensional array?](http://stackoverflow.com/questions/36794202/freaky-way-of-allocating-two-dimensional-array) best answers your question. – Lundin May 27 '16 at 13:53
  • @KevinDTimm No. It is not. I asked that question, and it has to do with the workings of reallocate(). This has to do with the syntax of pointer declarations. This, however, does look like a duplicate to the questions Klas Lindbäck and Lundin linked. – CircleSquared May 27 '16 at 13:54
  • @2501 It was turning into its proper within question of its own and I didn't want to harangue you until you until i got the new comprehensive explanation I needed. – CircleSquared May 27 '16 at 14:01
  • 1
    @CircleSquared I support your actions. – 2501 May 27 '16 at 14:03

3 Answers3

12

This is perfectly legal - you are allocating a pointer to an array of ten integers.

A good way to complete ... in your malloc is to use sizeof(*array) if you need only one array*:

int ( *array )[10] = malloc(sizeof(*array));

For instance, this makes sense: int *array = malloc(sizeof (int*) * 10);

This is an array of ints. The first syntax lets you create an array of arrays of ints - for example

int ( *array )[10] = malloc(50*sizeof(*array));

gives you a 50×10 array.

* Here is a good explanation of why sizeof(*array) is a good way of sizing your allocation.

Community
  • 1
  • 1
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • You may give a small note or possibly a link on why you used `sizeof *array`. – sjsam May 27 '16 at 13:16
  • 1
    @sjsam Good point, thanks! – Sergey Kalinichenko May 27 '16 at 13:19
  • " `int ( *array )[10] = malloc(50*sizeof(*array));` gives you a 50×10 array. " It sounds like you're saying that it would created a 2D array, but wouldn't that be a single array (sized 50x10)? And, wouldn't that force you to access the array with `array[x * y]` if you wanted to use in as a 2D array? – CircleSquared May 27 '16 at 17:50
  • 1
    @CircleSquared Technically, this would give you a 1D array of 50 1D arrays, 10 `int`s each. C lets you treat this array as a 2D array. It wouldn't force you to access the array with a single indexer: `array[indexUpTo50][indexUpTo10]` will work fine. [Demo](http://ideone.com/hSS3sR). – Sergey Kalinichenko May 27 '16 at 17:53
  • Thanks so much! Wow, I clearly need to revisit the books on this. – CircleSquared May 27 '16 at 18:51
  • @CircleSquared I am almost certain that this syntax is missing from the K&R book. The book explains allocation of jagged arrays at great length, but it does not talk about allocating arrays of fixed-size arrays at all. – Sergey Kalinichenko May 27 '16 at 19:01
7
int ( *array )[10] = malloc(...);

declares array as a pointer to a 10-element array of int; the pointer is initialized with the result of the malloc call. It's the same as writing

int (*array)[10] = NULL;
array = malloc( ... );

Remember that

T *p = malloc( sizeof *p * N );

will allocate enough storage to hold N instances of T and assign the resulting pointer value to p. This is true for any type T.

If we replace T with an array type like R [10], we get

R (*p)[10] = malloc( sizeof *p * N );

The semantics are exactly the same, all that's changed is the type of p; we're allocating enough storage to hold N instances of R [10].

Based on my understanding of C's syntax and grammar, this looks like nonsense.

Then you need to revisit that understanding. C declaration syntax is a lot more complex than most people think. See section 6.7 of the online C 2011 standard.

EDIT

Here's how the syntax breaks down:

int     (   *         array    )[     10     ]  = malloc( ... );
^       ^   ^           ^      ^^     ^      ^  ^ ^
|       |   |           |      ||     |      |  | |
|       | pointer     direct   ||     |      |  | assignment
|       |   |       declarator ||     |      |  | expression
|       |   |           |      ||     |      |  | |
|       |   +-----+-----+      ||     |      |  | |
|       |         |            ||     |      |  | |
|       |     declarator       ||     |      |  | |
|       |         |            ||     |      |  | |
|       +---------+------------+|     |      |  | |
|                 |             |     |      |  | |
|               direct          | assignment |  | |
|             declarator        | expression |  | |
|                 |             |     |      |  | |
|                 +-------------+-----+------+  | |
|                               |               | |
|                             direct            | |
|                           declarator          | |
type                            |               | |
specifier                   declarator          | initializer
|                               |               | |
|                               +---------------+-+
|                                               |
|                                          init-declarator
declaration                                     |
specifiers                              init-declarator-list
|                                               |
+----------------------+------------------------+
                       |
                   declaration

I'm omitting intermediate steps from 10 to assignment-expression and from malloc(...) to initializer because they'd just make the diagram harder to read.

John Bode
  • 119,563
  • 19
  • 122
  • 198
5

The address of an array and the address of its first element are equal each other.

So if you have an array as for example

int array[10];

then the values of the pointers p and q

int *p = array;

and

int ( *q )[10] = &array;

will be the same though the types of the pointers are different.

These values are equal to the addresses of the first elements of the arrays. In the first case the type of the element is int while in the second case the type of the element is int[10] But in the both cases it is the address of the allocated extent of memory that is not changed depending on how it is interpretated in C.

You can get the pointer p from the pointer q the following way

p = *q;

Take into account that function malloc returns a pointer to void that is of type void * that in C can be implicitly converted to a pointer of any other type.

Thus these statements

int ( *array )[10] = malloc( 10 * sizeof( int ) );

and

int *array = malloc( 10 * sizeof( int ) );

are valid in C.

On the other hand function free uses as its parameter again a pointer of type void *. And a pointer of other type can be implicitly converted to the type void *.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335