0

In this code, while we are dynamically allocating memory for the 2D array, after 4 address why it is taking a gap of 16 bytes but when we are statically allocating 2D array then it does not have such gap.... what is the reason behind this???

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

int main() 
{ 
    int r = 3, c = 4, i, j, count; 

    int stat[r][c];

    int *arr[r]; 
    for (i=0; i<r; i++) 
         arr[i] = (int *)malloc(c * sizeof(int)); 

    // Note that arr[i][j] is same as *(*(arr+i)+j) 
    count = 0; 
    for (i = 0; i <  r; i++) 
      for (j = 0; j < c; j++) 
         arr[i][j] = ++count; // Or *(*(arr+i)+j) = ++count 

    for (i = 0; i <  r; i++) 
      for (j = 0; j < c; j++) 
         printf("%d\n", *(arr+i)+j); 

    printf("\n\n");  
    for (i = 0; i <  r; i++) 
      for (j = 0; j < c; j++) 
         printf("%d\n", *(stat+i)+j); 

    /* Code for further processing and free the  
      dynamically allocated memory */

   return 0; 
} 
  • Probably overhead in the `malloc` call (e.g. embedding address into allocated chunk). – Fiddling Bits Mar 30 '20 at 17:06
  • 2
    `malloc()` needs to store the allocation size so that it knows how much to free when you call `free()`. – Barmar Mar 30 '20 at 17:07
  • 4
    More generally, there's no reason to expect sequential calls to `malloc()` to return contiguous memory blocks. – Barmar Mar 30 '20 at 17:08
  • 1
    There is no requirent for `malloc` to use any logic to its allocation that a caller can make sense of. The 2D array has no gaps *by definition*. – Weather Vane Mar 30 '20 at 17:09
  • when we are allocating 2d array dynamically why it is not contiguous – Pritam Adsul Mar 30 '20 at 17:10
  • Allocate once and it will be contiguous. – Fiddling Bits Mar 30 '20 at 17:13
  • It is not a 2D array, it is a 1D array of pointers, each pointing to a 1D array of integers. There are 3 calls to `malloc` and they are unrelated. – Weather Vane Mar 30 '20 at 17:17
  • This anwer to a C++ question: [Why do successive calls to new not allocate contiguous memory?](https://stackoverflow.com/a/25677719/4142924) gives 5 reasons that also apply to `malloc` in C code too. – Weather Vane Mar 30 '20 at 17:31
  • If you want to allocate an actual multidimensional array, see [**Correctly allocating multi-dimensional arrays**](https://stackoverflow.com/questions/42094465/correctly-allocating-multi-dimensional-arrays) – Andrew Henle Mar 30 '20 at 18:44

2 Answers2

2

Because you are not allocating a 2D array. You are allocating a set of 1D arrays, and those allocations do not have to be contiguous (most malloc implementations reserve some bytes to store the size of the allocated block).

To dynamically allocate a "true" 2D array where number of rows and columns aren't known until runtime, you'd do something like this:

stat (*arr)[c] = malloc( sizeof *arr * r );

that would be contiguous like any "normal" 2D array.

But...

Strictly speaking, this behavior is undefined - since arr points to a VLA, the sizeof *arr expression must be evaluated at runtime, not at compile time, and arr is not a valid pointer value at that point. I've never seen this fail on any implementation I've used, but that doesn't mean it won't fail somewhere. If c were constant instead, like

stat (*arr)[3] = malloc( sizeof *arr * r );

then there wouldn't be a problem, and this would be the preferred way to dynamically allocate an Nx3 array.

If you need all array elements to be contiguous (such that you could traverse the entire array with a pointer or something like that), then the safest option is to allocate your memory as a 1D array:

stat *arr = malloc( sizeof *arr * r * c );

and compute the offsets manually:

x = arr[ i * r + j ];

If you want the convenience of 2D notation, you could try creating a pointer and setting to point to the beginning of the array, something like

stat (*ptr)[c] = (stat (*)[c]) arr;

but that kind of pointer aliasing is also undefined if the pointer types are not compatible, and we've no reason to expect that a pointer to T is compatible with a pointer to an array of T.

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

The comments on your question have the most essential advice - don't worry about where malloc puts your memory. There is no assurance that it will be in any order. It may locate allocations in pursuit of various optimizations or speculations, and may vary from one execution to the next. If nothing else, other memory allocations, calls to free, garbage collection (in languages with GC, that is) between your calls to malloc will affect the location of the next allocation.

This can also vary with compiler, compiler options, OS, etc.

As for the specific reason your allocations have a 16 byte gap, that's impossible to say without more, and likely very deep, insight into your scenario. BTW, you didn't include output of your printf in your question.

But if I had to guess, I'd say the memory manager was aligning the allocations up with memory boundaries...perhaps a 32-byte or 64-byte boundary.

You're allocating 4 * sizeof(int). If an int is 4 bytes on your system, that's 16 bytes. If your malloc likes to line things up to 32 bytes, that might explain the 16-byte gaps you're seeing.

But again...this is just a guess. The simple answer is...you shouldn't care.

But if you DO care for some reason, you probably need to do your own allocation. malloc a much larger chunk of memory, and then manage your own pointers and allocations internally.

David Hempy
  • 5,373
  • 2
  • 40
  • 68