code :
#include <stdio.h>
#include <stdlib.h>
#define NUM_ROWS 3
#define NUM_COLS 2
int main() {
int **arr = (int **)malloc(NUM_ROWS * sizeof(int*));
printf("address of arr = %p\n",&arr);
printf("value inside arr = %p\n",arr);
for(int i=0;i<NUM_ROWS;i++) {
printf("arr + %d = %p\n",i,arr + i);
}
for(int i=0;i<NUM_ROWS;i++) {
arr[i] = (int *)malloc(NUM_COLS * sizeof(int));
printf("*(arr + %d) is initialized with = %p \n",i,arr[i]);
}
// access one element :
arr[2][1] = 4;
printf("arr[2][1] = %d\n", *(*(arr+2) + 1) );
for(int i = 0;i<NUM_ROWS;i++) {
free(arr[i]);
}
free(arr);
return 0;
}
Explanation :
Assume that:
- the size of any pointer = 4 Bytes
sizeof
(int)
= 4 Bytes
Therefore,
malloc(NUM_ROWS *
sizeof
(*int))
is basically malloc(12)
So, malloc
will return a void*
pointing to the first byte of the contiguous area of $12$ Bytes.
Assume that first Byte address is $2000$
int **arr = malloc(NUM_ROWS *
sizeof
(*int));
arr
is another pointer variable (just ignore ** for a moment)
we will assign value $2000$ to arr
Since arr
is a pointer we can do pointer arithmetic on arr
.
We also know that,
arr
+ offset = arr + offset *
sizeof
(*arr);
arr
is a double pointer. So if we dereference it one time (*arr
) it will again be a pointer (although single).
So, sizeof(*arr) = 4
according to our assumption.
Therefore,
arr+0 = 2000
arr+1 = 2004
arr+2 = 2008
Now,
Let's look at *(arr+i)
for i = 1
arr
is a double pointer
arr + 1
is also a double pointer
*(arr+1)
is a single pointer with size of $4$ Bytes.
We are reading a memory location of $4$ Bytes as shown below.
Currently, this location is uninitialized.
So we will again call malloc(NUM_COLS*sizeof(int))
or malloc(8)
which will allocate $8$ Bytes of a memory block and returns the address the of the first Byte. We will take that address and assign it to *(arr+1)
, as shown below.
Likewise, we will initialize all *(arr+i)
or arr[i]
for i = 0,1,2
Finally, this is the memory layout.
Output in an actual system :
address of arr = 0023FF10
value inside arr = 004915B0
arr + 0 = 004915B0
arr + 1 = 004915B4
arr + 2 = 004915B8
*(arr + 0) is initialized with = 00491590
*(arr + 1) is initialized with = 004915C8
*(arr + 2) is initialized with = 004915D8
arr[2][1] = 4
NOTE :
casting malloc
is not required in c : But we should use it for portability issue.