James February 2016

Variable size two dimensional array in C

So I've been trying to store a PPM file in a program to be manipulated, I successful stored everything up to the colors, I've made progress on the colors.

During asking a question on stack overflow (For loop stops for no reason) I was convinced that my method was a bit shoddy, however I don't understand the reasoning for using the follow:

COLOR (*colors)[width] = malloc( sizeof(COLOR[height][width]) );

can someone break down exactly what this line of code is doing and explain what type it is. So I can store it in a struct and successful return it.

Example: previously I used pointers to pointers, where I allocated a height and for each pointer I allocated a width. This means that for each pointer I could create a color, increment it along the width until Im at the end, then reset the pointer and increment the height and loop. After I got the full image I return it to store it in the follow:

typedef struct {
    char code[CODE_LENGTH];
    COMMENT *commentPPM;
    int width, height, max;
    COLOR **colorValues;
} PPM;

using:

ppmFile->colorValues = getColors(fd, ppmFile->width, ppmFile->height);

and

typedef struct{
    int red, green, blue;
} COLOR;

COLOR * getNextColor(FILE *fd);

COLOR **getColors(FILE *fd, int width, int height){
    printf("\nentered get colors");
    COLOR **colors = malloc(sizeof(COLOR*)*height);
    printf("\nallocated %d space height",height);

    int i,j;
    for(i = 0; i < height; i++, colors++){
        *colors = malloc(sizeof(COLOR)*width);
        printf("\nallocated %d space width",width);
        for(j = 0; j < width; j++, *(colors++)){
            printf("\nlooping through to get the colors for point (%d,%d)", j,i); 
            //*colors = getNextColor(fd);
        

Answers


Lundin February 2016

In order to understand this, you need to first understand the concepts:

  • Array pointers (not to be confused with pointer to first element)
  • Variable-length arrays, also known as VLAs.

Given that already you know what the above is, then the most formally proper way to do this is to declare an array pointer to a 2D VLA:

COLOR (*colors)[height][width];

And when you call malloc, you tell it to allocate enough space for such an array:

malloc( sizeof(COLOR[height][width]) )

You would then end up with

colors = malloc( sizeof(COLOR[height][width]) );

However, since colors in this example is an array pointer, you would have to de-reference it each time you wish to access the array:

(*colors)[i][j] = something;

This syntax is not practical and also hard to read.

Therefore, you can use another trick and skip the inner-most dimension when you declare the array pointer. Instead of a pointer to a 2D array, you could skip the inner-most dimension and just declare an array pointer to a 1D array:

COLOR (*colors)[width]

but use this with the very same malloc call as before. Because now you can take advantage of array pointer arithmetic:

colors[i][j] = something;

Which essentially means, "in my array-of-arrays, give me array number i, item number j".

It works for the same reason as int* x = malloc(sizeof(int[n])); ... x[i] = something; works, which of course gives you int number i.

Post Status

Asked in February 2016
Viewed 2,347 times
Voted 10
Answered 1 times

Search




Leave an answer