1

The following snippet declares a 2-D array of 4 X 10 using malloc function

/* Declare a pointer to an array that has 10
ints in each row. */
int (*p)[10];
register int i, j;
/* allocate memory to hold a 4 x 10 array */
p = malloc(40*sizeof(int));

But I do not understand how does p become a 2-D array. Initially p is declared to be an array of pointers that point to int. What happens after the call to malloc ? I am unable understand this.

Ismael Luceno
  • 2,055
  • 15
  • 26
saplingPro
  • 20,769
  • 53
  • 137
  • 195

3 Answers3

3

The memory, worth 40 ints, is reserved to the pointer p. p points at his memory block. It so happens that p chooses to organize this memory as 10 equal parts, each of which happen to hold 4 ints' worth.

That's if this code is actually correct. My C is very rusty at this point.

Satya
  • 4,458
  • 21
  • 29
3

In C, pointers and arrays are not the same, despite looking very similar. Here p is of type "pointer to array of 10 ints". You're using it as a "pointer to array of 4 arrays of 10 ints", which is a single block of memory (the only pointer is the outermost pointer). It's basically a dynamically allocated int[4][10].

The trick to reading these definitions is to realize that they're written the same way you use the item. If you have:

*x[10];

The array subscript is applied first, then the pointer dereference. So it's an array of pointers if you define int *x[10]. If you use parenthesis to override normal precedence, you can get the pointer dereference to happen first, so you have a pointer to an array.

Confusing? It gets worse. In function arguments, the outermost array of a function parameter is converted into a pointer.

int *p[10]; // array of 10 pointer to int
int (*p)[10]; // pointer to array of 10 ints
void foo(int *p[10] /* pointer to pointer to int */);
void foo(int (*p)[10] /* pointer to array of 10 ints */);

Further, arrays are converted to pointers when you use them.

int x[10]; // array of 10 int
sizeof(x); // 10 * sizeof(int)
int *y = x; // implicitly converts to a pointer to &x[0]!
sizeof(y); // sizeof(int *)

This means that you can allocate memory for an array of arrays, then let that implicitly convert to a pointer to an array, which you in turn use as if it were an array of arrays!

Anyway, this is all very confusing so please do not ever use this in production code - at least, not without a clarifying typedef:

typedef int vector[3];
vector *array_of_vectors; // actually a pointer to a vector, 
                          // but you can use it as an aray to a vector if enough
                          // memory is allocated
bdonlan
  • 224,562
  • 31
  • 268
  • 324
  • Here: `int x[10]; // pointer to 10 int` x is an array of 10 ints. – Alexey Frunze Sep 22 '12 at 05:56
  • +1, but I don't find it confusing: there are just three rules to remember. (1) arrays are not pointers unless (2) they are the outermost `[]` specification of a function parameter, or (3) used as values in expressions. – Jens Gustedt Sep 22 '12 at 07:14
0

First, some background information:

Except when it is the operand of the sizeof, _Alignof, or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" is converted ("decays") to an expression of type "pointer to T", and its value is the address of the first element in the array. For example, given the array

int a[10];

anytime the expression a appears in the code, its type will be converted from "10-element array of int" to "pointer to int", or int *, except for cases like sizeof a, _Alignof a, and &a. If we have a 2D array of T, such as

int a[10][10];

the expression a will be converted from type "10-element array of 10-element array of int" to "pointer to 10-element array of int", or int (*)[10] (look familiar? that's the type of your pointer p).

If we want to dynamically allocate an N-element array of type T, we write something like

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

sizeof *p is equivalent to sizeof (T). In this particular case, type T is "10-element array of int", or int [10]. We want to allocate 4 such arrays, so we can write

int (*p)[10];
p = malloc(4 * sizeof *p);

This allocates space for 4 10-element arrays of int, and assigns the result to p. (sizeof *p == sizeof (int [10])).

So how does this become a 2D array?

Remember that the expression a[i] is equivalent to *(a + i); we find the address of the i'th element of type T following a and dereference the result. In this case p[i] gives us the address of the ith 10-element array of int following p. Since we dereference the pointer as part of the subscript operation, the type of the expression p[i] is "10-element array of int". Thus we can subscript this expression again and get p[i][j].

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