1

I wanted achieve 2D array with double pointer and I expected each array to be contiguous in memory space. So there should be 20-bytes between each array. But following code giving different result which I supposed. Can anyone explain why each array not be contiguous?

#define ROW 5
#define COL 5

int main() {
  int **ptr = (int **)malloc(sizeof(int *)*ROW);
  for(int i=0; i<ROW; i++) {
    *(ptr+i) = (int *)malloc(sizeof(int)*COL);
  }

  printf("%p\n", *(ptr+0));
  printf("%p\n", *(ptr+1));
  printf("%p\n", *(ptr+2));
  printf("%p\n", *(ptr+3));

return 0;
}

Output :

0000 0df3 4325 1450
0000 0df3 4325 1470
0000 0df3 4325 1490
0000 0df3 4325 14b0

Expected :

0000 0df3 4325 1450
0000 0df3 4325 1464
0000 0df3 4325 1478
0000 0df3 4325 148c
6
  • 4
    Each 1D array should have contiguous elements, and the array of pointers to them will be contiguous too. But there is no requirement for each 1D array to be contiguous with other 1D memory allocations. You'll need an actual 2D array to ensure that. Commented Apr 19, 2024 at 19:50
  • 1
    malloc() allocates each array at an aligned address so it can be used for any datatype. There also may be some overhead bytes. So you shouldn't expect each array to be right next to the previous one. Commented Apr 19, 2024 at 19:53
  • 2
    BTW, your code will be more understandable if you write ptr[i] instead of *(ptr+i). Commented Apr 19, 2024 at 19:54
  • 1
    Side note: Should I cast the result of malloc (in C)? Commented Apr 19, 2024 at 19:57
  • 1
    Side note: According to the ISO C standard, the %p printf specifier requires an argument of type void *. By passing an argument of int * instead without a cast to void *, according to the C standard, you are invoking undefined behavior. Nevertheless, on most modern platforms, the cast to void * is unnecessary. Commented Apr 19, 2024 at 20:20

3 Answers 3

2

Can anyone explain why each array not be contiguous?

Subsequent allocations do not need to be be contiguous (in size). Each allocation from malloc() and some friends must meet an alignment requirement:

The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement ... C2x § 7.24.3 1

The fundamental alignment requirement may be found with:

#include <stddef.h>
#include <stdio.h>

printf("%zu\n", alignof(max_align_t));

Common values are 4, 8, 16. So a pointer difference of multiples of 4, 8, 16 is quite common.
A pointer difference of 20 from allocations of 20 bytes is most uncommon.

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

Comments

1

What you are doing is not allocating a 2D array (i.e. an array of arrays). What you are doing instead is allocating a 1D array of pointers which each point to a 1D array of int elements. These arrays could be anywhere in memory, because the memory blocks returned by malloc are not necessarily adjacent to each other.

If you want to allocate an actual 2D array, you should use a single call to malloc, so that all of the memory is guaranteed to be contiguous. Here is an example:

#include <stdio.h>
#include <stdlib.h>

#define NUM_ROWS 5
#define NUM_COLS 5

int main( void )
{
    int (*ptr)[NUM_COLS] = malloc( sizeof *ptr * NUM_ROWS );
    if ( ptr == NULL )
    {
        fprintf( stderr, "memory allocation failure!\n" );
        exit( EXIT_FAILURE );
    }

    printf( "%p\n", (void*) ptr[0] );
    printf( "%p\n", (void*) ptr[1] );
    printf( "%p\n", (void*) ptr[2] );
    printf( "%p\n", (void*) ptr[3] );

    free( ptr );
}

This program has the following output:

0x179c2a0
0x179c2b4
0x179c2c8
0x179c2dc

As you can see, the sub-arrays are now adjacent to each other. The difference between all addresses is 20 bytes.

In the declaration int (*ptr)[NUM_COLS], I have declared ptr to be a pointer to an array of NUM_COLS elements of type int. I did this because in C, it is common to reference arrays using pointers to the first element of the array, so that you can use the [] subscript operator on the pointer, in order to access individual elements of the array.

Comments

1

"I wanted achieve 2D array with double pointer"

Stop and think about what a double pointer actually is.

It is a pointer that points to the first of one-or-more contiguous pointers. It does not, itself, point to data variables. (It may hold NULL itself, pointing to nothing!)

The "other pointers" usually point to the first of one-or-more contiguous data variables. (It is perfectly legitimate for some of those other pointers to be NULL.)

Suggest you draw a diagram, using boxes and arrows, to see the difference between what your code does (with its multiple calls to malloc()) and what @Andreas's code does with its single heap allocation.


Make a habit of always typing malloc() and free() as a pair, similar to always entering { and } as a pair, so that you don't forget to free() allocated heap blocks. You'll save yourself countless hours of frustration when a memory leak makes itself known after you've completed writing several thousand lines of code. (Such problems easily go unnoticed in what appears to be perfectly correct code...)

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.