25
votes

I am writing C code and I would like to heap allocate 512*256 bytes. For my own convenience I would like to be able to access the elements with the syntax array[a][b]; no arithmetic to find the right index.

Every tutorial I see online tells me to create an array of pointers that point to arrays of the rows I want in my array. This means that each subarray needs to be malloc'd and free'd individually. I am interested in a solution that only requires one call to malloc and one call to free.(Thus all elements are contiguous) I think this is possible because I will not be constructing a jagged array.

I would appreciate if anyone could share the syntax for declaring such an array.

7
Is C++ an option? You could create a simple C++ objects that overloads the indexing operator. - Richard J. Ross III
@RichardJ.RossIII: Is that really a valid response to a question of "how do I do this in C?" (realizing that you did leave it as a comment). I'll take C over C++ any day thank you. - Ed S.
@EdS. while you may prefer C, C++ is better in quite a few situations, and this would be one of them. I left it as a comment simply to determine if it would be an option. - Richard J. Ross III
@RichardJ.RossIII: C++ is better for allocating a 2d array? huh? I don't think so, this is easily doable in C, no C++ operator overloading required. - Ed S.
See my answer; unlike the others it actually does what you ask for. - R.. GitHub STOP HELPING ICE

7 Answers

42
votes

Well, if you want to allocate array of type, you assign it into a pointer of that type.

Since 2D arrays are arrays of arrays (in your case, an array of 512 arrays of 256 chars), you should assign it into a pointer to array of 256 chars:

char (*arr)[256]=malloc(512*256);
//Now, you can, for example:
arr[500][200]=75;

(The parentheses around *arr are to make it a pointer to array, and not an array of pointers)

14
votes

If you allocate the array like this, it requires two calls to free, but it allows array[a][b] style syntax and is contiguous.

char **array = malloc(512 * sizeof(char *));
array[0] = malloc(512*256);
for (int i = 1; i < 512; i++)
    array[i] = array[0] + (256 * i);

See array2 here for more information: http://c-faq.com/aryptr/dynmuldimary.html

14
votes

This is easy assuming you don't need compatibility with the ancient C89 standard (among current C compilers, only MSVC and a few embedded-target compilers are that backwards). Here's how you do it:

int (*array)[cols] = malloc(rows * sizeof *array);

Then array[a][b] is valid for any a in [0,rows) and b in [0,cols).

In the language of the C standard, array has variably-modified type. If you want to pass the pointer to other functions, you'll need to repeat this type in the function argument list and make sure that at least the number of columns is passed to the function (since it's needed as part of the variably-modified type).

Edit: I missed the fact that OP only cares about a fixed size, 512x256. In that case, C89 will suffice, and all you need is:

int (*array)[256] = malloc(512 * sizeof *array);

The exact same type can be used in function argument lists if you need to pass the pointer around between functions (and also as a function return type, but for this use you might want to typedef it... :-)

5
votes

Since you know the size of the array ahead of time, you could create a struct type that contains a 521x256 array, and then dynamically allocate the struct.

4
votes

It is possible to dynamically allocate the same kind of multidimensional array that

static char x[512][256];

gives you, but it's a wee tricky because of type decay. I only know how to do it with a typedef:

typedef char row[512];
row *x = malloc(sizeof(row) * 256);

This only lets you determine the size of the second dimension at runtime. If both dimensions can vary at runtime, you need a dope vector.

2
votes

If you know the size of the array, you can typedef it, and make a pointer to it. Here is a short snippet that demonstrates this use:

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

typedef int array2d[20][20];

int main() {
    int i,j;
    array2d *a = malloc(sizeof(array2d));
    for(i=0;i!=20;i++)
        for(j=0;j!=20;j++)
            (*a)[i][j] = i + j;

    for(i=0;i!=20;i++)
        for(j=0;j!=20;j++)
            printf("%d ",(*a)[i][j]);
    free(a);
    return 0;
}
0
votes

All great answers. I just have one thing to add for old weirdos like me who enjoy "retro" coding 16 bit with old compilers like Turbo C, on old machines. Variable length arrays are wonderful, but not needed.

    char (*array)[81];
    int lineCount;

    /* Go get your lineCount.*/
    lineCount = GetFileLines("text.fil");

    array = malloc(lineCount * 81);

This is how we did "VLA" back in the olden days. It works exactly the same as

    char (*array)[81] = malloc(lineCount * 81);  /* error pre C99 */

without the luxury of VLA.

Just my old and tarnished 2 cents.