2

everyone: I just come across an approach to allocate a 2D matrix in C. While practicing it, I'm confused about an unknown bug.

here is the function, first version:

//first version
static int ** my2DAlloc(int rows, int cols){
    int ** array;
    int * array_head;
    int i;
    int len = sizeof(int*)*rows + sizeof(int)*rows*cols + 1;
    array = (int**)malloc( len );
    memset(array, 0, len);

    array_head = (int *) (array + rows);
    for(i=0; i<rows; i++)
        array[i] = array_head + i*cols ;

    return array;
}

I don't have any problem with this version. However, I've tried to change the code a little, as the following:

//second version
static int ** my2DAlloc(int rows, int cols){
    int ** array;
    int * array_head;
    int i;
    int len = sizeof(int*)*rows + sizeof(int)*rows*cols + 1;
    array = (int**)malloc( len );
    memset(array, 0, len);

    //array_head = (int *) (array + rows);
    for(i=0; i<rows; i++)
        array[i] = (int *) (array + rows + i*cols);   // <--- the major difference

    return array;
}

Regarding this second version, it seems fine to write data to the matrix and read data out. But when I try to free the allocated space, I get system error like:

free(): invalid next size (fast): 0x00000000020df010

It seems to be some memory error. But I could not figure out the problem. Could anyone help me out?

Thanks & Regards

MyCoy
  • 61
  • 5
  • How do you write the line of code where you free the space? – Burstful Oct 18 '17 at 23:23
  • `array` is `int**`. `array_head` is `int*`. Both are different. – BLUEPIXY Oct 18 '17 at 23:26
  • Do you really intend to return a pointer to a pointer of int? As in, are you looking for an array of int pointers? – jwdonahue Oct 18 '17 at 23:35
  • [don't cast malloc](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) – Barmar Oct 18 '17 at 23:38
  • If it's a 2D matrix of integers your looking for, then len should be sizeof(int) * rows * cols. – jwdonahue Oct 18 '17 at 23:40
  • @jwdonahue What this seems to be is a 2D matrix of integers, but it has a header containing pointers to each row. – Barmar Oct 18 '17 at 23:41
  • 1
    So it's like a matrix implemented as an array of pointers to rows, but it ensures that the rows are contiguous with each other and the pointer array. – Barmar Oct 18 '17 at 23:43
  • 1
    The only value I can see in this design is that it's good for locality, and you can free the entire thing with one call to `free()`. – Barmar Oct 18 '17 at 23:44
  • @Barmar, I agree, but I just wanted to make sure that this is the OP's intent. – jwdonahue Oct 18 '17 at 23:46
  • `int len = sizeof(int*)*rows + sizeof(int)*rows*cols + 1;` is wrong size for various reasons: First drop the +1. 2nd type should be `size_t` 3rd: most important: code does not insure proper aliment of the `int`. This _may_ work for OP, but is is not correct in general. – chux - Reinstate Monica Oct 19 '17 at 01:52
  • The code will fail on a platform where `sizeof(int) != sizeof(int *)`. This would write out of bounds for access to latter parts of the array, causing heap corruption (and perhaps therefore, failure of free) – M.M Oct 19 '17 at 03:06
  • @M.M Once again thanks for the good feed back – chux - Reinstate Monica Oct 19 '17 at 03:28
  • See [C pass variable size 2-D array to function](https://stackoverflow.com/a/42652072/2410359) – chux - Reinstate Monica Oct 19 '17 at 03:29
  • I just use free(array) to free the allocated memory – MyCoy Oct 20 '17 at 00:54

1 Answers1

3

The problem in the second version is that you're doing the pointer arithmetic on an int ** instead of int *, because you have the cast outside the arithmetic.

for(i=0; i<rows; i++)
    array[i] =  ((int *)(array + rows) + i*cols);   // <--- the major difference
Barmar
  • 741,623
  • 53
  • 500
  • 612