3

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.

15
  • 4
    You have too many restrictions - therefore this is impossible. Commented May 23, 2015 at 21:20
  • 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? Commented May 23, 2015 at 21:24
  • 2
    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. Commented May 23, 2015 at 21:24
  • 2
    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). Commented May 23, 2015 at 21:27
  • 1
    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. Commented May 23, 2015 at 22:10

2 Answers 2

5

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.

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

5 Comments

good: double (*A)[rows][cols] = malloc(sizeof *A); *A[1][2] = 100.0; printf("%lf\n" , *A[1][2]);
This seems to work fine! I have a question though: When I use: double *A[n][m] = malloc(sizeof *A); I get the error: error: variable-sized object may not be initialized However, when I don't write the brackets when printing it, it is ok. Why is that?
@Zelphir, because these are two completely different animals. The one that gives you the error is a 2D table of pointers, whereas the correct one is a pointer to a 2D table.
It is because in one case the * is grouped/attached to the variable name and dereferences A and in the other case it is grouped/attached with the type and it makes it a pointer type -- right?
@Zelphir, yes, exactly.
1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.