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.

9
  • 3
    Wasn't my example clear? :-( You could have told me and I would try to explain it further. Commented May 27, 2016 at 13:06
  • 3
    It looks weird, but int (*foo)[10] declares foo as a pointer to an array of 10 ints. Remove () and int *foo[10] declares foo as an array of 10 pointers to ints. Commented May 27, 2016 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. Commented May 27, 2016 at 13:22
  • 2
    I believe Freaky way of allocating two-dimensional array? best answers your question. Commented May 27, 2016 at 13:53
  • 1
    @CircleSquared I support your actions. Commented May 27, 2016 at 14:03

3 Answers 3

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.

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

6 Comments

You may give a small note or possibly a link on why you used sizeof *array.
@sjsam Good point, thanks!
" 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 Technically, this would give you a 1D array of 50 1D arrays, 10 ints 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.
Thanks so much! Wow, I clearly need to revisit the books on this.
|
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.

Comments

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 *.

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.