0

I know this question was answered but it somehow doesn't work for me. I dynamically allocate memory for array like this:

arr = (int**)(malloc(rows*sizeof(int*)));
arr[0] = (int*)(malloc(rows*columns*sizeof(int))); // <-- THIS DOESN'T WORK

printf("\nArray: \n");
while(fscanf(fp, "%d", &num) == 1) {   
    //arr[row] = (int*)(malloc(columns*sizeof(int))); <---THIS WORKS
    arr[row][col] = num;
    printf("%d ", arr[row][col]);
    if((++col == columns)){
        row++;          
        col = 0;
        printf("\n");
    }
}

It throws segmentation fault after 4th row, if matrix is 6x6. Any advice? Thanks

EDIT: See: http://www.geeksforgeeks.org/dynamically-allocate-2d-array-c/ point number 4. If I do it like in point 3, it works. But I need it like in 4.

Wlad
  • 410
  • 1
  • 9
  • 27

4 Answers4

7

There exists no case where you should use fragmented malloc calls like you do. It is wide-spread but bad and incorrect practice. As you point out, it will not give you a true 2D array in adjacent memory, but rather a fragmented, slow mess.

How to do this properly:

In standard C, write

int (*arr)[rows][columns] = malloc (sizeof(*arr));
(*arr)[r][c] = something;
...

free(arr);

or if you prefer to use syntax which is easier-to-read (but perhaps harder to understand):

int (*arr)[columns] = malloc (sizeof(int[rows][columns]));
arr[r][c] = something;
...

free(arr);

In obsolete versions of C, you will have to write a "mangled array":

int* arr = malloc(rows * columns * sizeof(*arr));
arr[r*c] = something;
...

free(arr);
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Why you call the last one mangled array i do not know. Something else confused me. In the first case `sizeof(*arr)` equals 4 bytes (or the word size of the computer), does it equal `rows * columns * sizeof(int)`? – KeyC0de Sep 09 '17 at 07:37
  • 1
    @Nik-Lz It is called "mangled" because you can't use regular 2D array syntax when accessing it, but have to calculate the array index. `sizeof(*an_array_pointer)` does _not_ equal 4 bytes, but the size of the array. This is a difference between array pointers and regular pointers. – Lundin Sep 11 '17 at 06:13
5

To allocate a contiguous memory, you'll have to use

arr  = malloc(sizeof(int *) * rows);
arrayData = malloc(sizeof(int) * columns * rows);

for(i = 0; i < rows; i++)
     arr[i]  = arrayData + i * columns ;

To deallocate you'll need to have

free( arrData );
free( arr );

See here

P0W
  • 46,614
  • 9
  • 72
  • 119
2

You need to allocate memory for each row, not just the first row. Replace

arr[0] = (int*)(malloc(rows*columns*sizeof(int)));

with

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

The changes made here are:

  1. All the rows will be allocated columns * sizeof(int) bytes of memory.
  2. Casting the result of malloc is pointless in C. I've removed it.

You might need to add a check in the loop to prevent an overflow. Something like

if(row == rows)
{
    puts("Matrix full; Exiting loop...");
    break;
}

The fixed code would be

int i, row = 0, col = 0;
int rows = 6, columns = 6; /* For 6x6 matrix */

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

printf("\nArray: \n");
while(fscanf(fp, "%d", &num) == 1) {   
    arr[row][col] = num;
    printf("%d ", arr[row][col]);
    if(++col == columns){
        row++;          
        col = 0;
        printf("\n");
    }
    if(row == rows)
    {
        puts("Matrix full; Exiting loop...");
        break;
    }
}
Spikatrix
  • 20,225
  • 7
  • 37
  • 83
  • Your solution is already in my question, see line with comment "<-- THIS WORKS". But if I do it like this, every 1D array of 2D array would be in different place of memory. See: http://www.geeksforgeeks.org/dynamically-allocate-2d-array-c/ point number 4. – Wlad Oct 05 '15 at 06:11
  • You can't do it the way you want to – Iharob Al Asimi Oct 05 '15 at 06:14
  • @iharob Well....ok, everyone seems to think the same, but can you give me a hint why this can't be done? – Wlad Oct 05 '15 at 06:27
  • @Wlad Whoa. That fourth method is *really* confusing at first glance. Try `int i; for(i = 0; i < rows; i++) arr[i] = (arr[0] + i * columns);` just after `arr[0] = (int*)(malloc(rows*columns*sizeof(int)))` in your code. – Spikatrix Oct 05 '15 at 06:41
  • However, this doesn't allocate a 2D array in adjacent memory cells. – Lundin Oct 05 '15 at 06:45
  • @Lundin Wouldn't [this](http://stackoverflow.com/questions/32942134/2d-array-as-contiguous-block-of-memory/32942196?noredirect=1#comment53710353_32942196) do it? – Spikatrix Oct 05 '15 at 06:54
  • @CoolGuy Forget about that "geeks for dinosaurs" link. 1999 is upon us, time to party, there's a new C standard. See my answer for better alternatives. – Lundin Oct 05 '15 at 06:56
2

For a 6x6 matrix, dynamic memory is overkill. You should simply use:

int arr[rows][cols];

This is much simpler, cleaner, quicker, less error prone and generally all round safer — as long as you keep the matrix size small enough that it easily fits on the stack. If you need a large matrix (say from 1 MiB upwards, but you'll need to tune your threshold to suit your systems), then dynamic memory is relevant.

You can make the single allocation to arr[0] work, but you have to do explicit assignments to each of arr[1] through arr[5]. I did it this way:

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

int main(void)
{
    int rows = 6;
    int cols = 6;
    int **arr = (int**)(malloc(rows*sizeof(int*)));
    arr[0] = (int*)(malloc(rows*cols*sizeof(int)));

    for (int i = 1; i < rows; i++)
        arr[i] = arr[i-1] + cols;

    printf("\nArray: \n");
    for (int i = 0; i < rows; i++)
    {   
        for (int j = 0; j < cols; j++)
            arr[i][j] = (i+1) * (cols + 1 - j);
    }

    for (int i = 0; i < rows; i++)
    {   
        for (int j = 0; j < cols; j++)
            printf("%3d", arr[i][j]);
        putchar('\n');
    }

    free(arr[0]);
    free(arr);
    return(0);
}

Sample output:

Array: 
  7  6  5  4  3  2
 14 12 10  8  6  4
 21 18 15 12  9  6
 28 24 20 16 12  8
 35 30 25 20 15 10
 42 36 30 24 18 12

Running valgrind gives a clean bill of health.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • However, this doesn't allocate a 2D array in adjacent memory cells. – Lundin Oct 05 '15 at 06:45
  • The data cells are a single contiguous array. – Jonathan Leffler Oct 05 '15 at 06:46
  • Oh right... only saw the pointer array allocation and dismissed it. Well anyway, this code is complete obscure, why would you ever want to write something like this? Just allocate an adjacent chunk of memory, no need for the array of pointers. – Lundin Oct 05 '15 at 06:50
  • The OP wanted (or, at least, used) an array of pointers; I fixed up what he said doesn't work (and it didn't work because 83% of the pointers were uninitialized) so it does work. – Jonathan Leffler Oct 05 '15 at 06:52