3
votes

I have a simple question, but the answer seems to be very difficult to find:

How do I create a true 2D array in C (not C++), dynamically sized (size not known at compile time), not an array of pointers, on the heap, so that I can put that allocation into a separate function and return the allocated array, without receiving any warnings from gcc -Wall?

I've found numerous other questions here on SO and in other forums, but the answers all had some flaw:

  • I saw many answers, which showed how to initialize an array of pointers, which according to some comments can lead to memory fragmentation and needs a loop to be freed when not used anymore.
  • I don't want to only have a predefined size of the array, but want to use it in some loops, creating arrays of many sizes.
  • I don't want the values in the array to be predefined either, they're calculated while the program is running.
  • I read about the layout in the memory, which can be different when using some methods of creating the array, while one can still use the array like this: a[y][x]. I want my array to have the memory layout of a true 2D array as well.

What is the right way to achieve allocation of such a true 2D array?

EDIT#1: The return type of the allocation method can be a pointer to the allocated array.

2
You have too many restrictions - therefore this is impossible.Ed Heal
I can't believe this cannot be done in C o.0 I mean these are pretty normal requirements. I simply want to do it propperly. Maybe you can tell which of my requirements makes it impossible?Zelphir Kaltstahl
What you are trying to do makes no sense, you should apparently use fortran or a language more suited to what you want, because I suspect that you are worrying about passing the data to fortran. Also as @EdHeal said, if you do it with one of your restrictions, then it's impossible to apply the other, simply like that it's not possible.Iharob Al Asimi
If you want an array of arrays, you need to know at least one dimension at compile-time. This is necessary or the compiler wouldn't know where &array[x][y] is. (To compute the address array + x, sizeof(array[0]) must be known).molbdnilo
In standard C, the closest you can get is to create a struct with number of rows, number of columns, and a pointer to an allocated 1D array, and functions (possibly macros) to use the 1D array as a 2D array.rcgldr

2 Answers

5
votes

You don't need a special function. Just do it like this

double (*A)[n][m] = malloc(sizeof *A);

As of C99, here n and m can be any positive integer expressions you want.

Such a thing is a pointer to a VLA, variable length array.

1
votes

I know that this is not the perfect answer; but I hope it will be helpful.

#include <stdio.h>
#include <stdlib.h>
#define ELEM(myArr,X,Y) (myArr->arr[myArr->cols * X + Y])
#define FREE_MY_ARR(myArr) \
    if(myArr){if(myArr->arr) free(myArr->arr);  free(myArr);}
    typedef struct myArr
    {
        int rows , cols;
        int * arr;
    } myArr;

    myArr * create_my_arr(int rows , int cols)
    {
        myArr * my_arr = malloc(sizeof(myArr));
        my_arr->rows =rows;
        my_arr->cols=cols;
        my_arr->arr= malloc(rows * cols * sizeof(*my_arr->arr));
        return my_arr;
    }

    int main()
    {
        int rows = 4 , cols = 5;
        myArr * my_arr = create_my_arr(4,5);
        int i , j ;
        for(i = 0 ; i < rows;i++)
            for(j = 0 ; j < cols;j++)
            {
                ELEM(my_arr , i , j) = cols * i + j; // 0,1,2,3,4,5,6,7,8,...etc
            }
        //print array.
        for(i = 0 ; i < rows;i++)
        {
            for(j = 0 ; j < cols;j++)
            {
                printf("arr[%d,%d]=%d\t" , i , j , ELEM(my_arr ,i , j));
            }
        printf("\n");
        }
        FREE_MY_ARR(my_arr);
       return 0;
    }

output:

   gcc -o s s.c &&s
    arr[0,0]=0      arr[0,1]=1      arr[0,2]=2      arr[0,3]=3      arr[0,4]=4
    arr[1,0]=5      arr[1,1]=6      arr[1,2]=7      arr[1,3]=8      arr[1,4]=9
    arr[2,0]=10     arr[2,1]=11     arr[2,2]=12     arr[2,3]=13     arr[2,4]=14
    arr[3,0]=15     arr[3,1]=16     arr[3,2]=17     arr[3,3]=18     arr[3,4]=19