1
votes

For my Project I need to read an PPM(P3) image into memory. Because I want to rotate the input picture and therefore I would like to go through an x and y axis/array.

First I read the values of the image into an "unsigned char" since the color values used are only between 0 and 255 and to save memory I convert them into unsigned chars.

Every pixel in the PPM image has a red, green, blue values.

For this, I created this typedef struct.

typedef struct{
    unsigned char red;
    unsigned char greed;
    unsigned char blue;
} color;

I tried to make a simple 2-dimensional array like this:

color inputColor[pictureHeight][pictureWidth];

But this fails very fast when the pictures get bigger. I am trying to make it work, so I can allocate that 2d array with malloc. One attempt was:

color *inputColor[pictureHeight][pictureWidth];

//Allocating memory
for (int y = 0; y < pictureHeight; y++){
    for (int x = 0; x < pictureWidth; x++){
        inputColor[y][x] = malloc(sizeof(color));
    }
}

// Here i am copying values from an inputStream to the structure
int pixel = 0;
for (int y = 0; y < pictureHeight; y++){
    for (int x = 0; x < pictureWidth; x++){
        inputColor[y][x]->red = inputMalloc[pixel];
        pixel++;
        inputColor[y][x]->green = inputMalloc[pixel];
        pixel++;
        inputColor[y][x]->blue = inputMalloc[pixel];
        pixel++;
    }
}

But it fails again in the first line...

How can a 2-dimensional struct array be allocated with malloc, so the picture sizes don't matter that much any more?

Right now it fails around a picture size of 700x700 pixels.

3
color (*inputColor)[pictureWidth] = malloc(pictureHeight * sizeof *inputColor);. use it with inputColor[y][x].red...mch
I have tried that, but from this I get "Segmentation fault (core dumped)".TheTrashinger
Assuming you have a C99-compliant compiler: Correctly allocating multi-dimensional arraysAndrew Henle
@mch: Make that an answer.R.. GitHub STOP HELPING ICE

3 Answers

3
votes

Double pointer solutions have a very weak point when considering images. They cannot be transferred directly to the screen memory or accessed fast way.

Much better is to use a pointer to array.

typedef struct{
    unsigned char red;
    unsigned char greed;
    unsigned char blue;
} color;

int main(void)
{

    size_t pictureHeight = 600, pictureWidth = 800;

    color (*inputColor)[pictureHeight][pictureWidth];

    inputColor = malloc(sizeof(*inputColor));
}
1
votes

Just allocate a double pointer and allocate memory to it:

color **inputColor;

inputcolor= malloc(sizeof(color*)*pictureHeight);
for (int y = 0; y < pictureHeight; y++){
        inputColor[y] = malloc(sizeof(color)*pictureWidth);
   
}
1
votes

The pointer to array approach posted by mch, I believe would be the best approach:

#include <stdlib.h>

color (*inputColor)[pictureWidth] = malloc(pictureHeight * sizeof *inputColor);

The access is the same as you are using, inputColor[y] for line and inputColor[y][x] for column, inputColor[y][x].red to access struct member.

Since you stated you can't make it work, you can try using the pointer to pointer method, though slower, it may be easier to understand and apply:

color **inputColor;

inputColor = malloc(pictureHeight * sizeof *inputColor);

for (int y = 0; y < pictureHeight; y++)
{
    inputColor[y] = malloc(pictureWidth * sizeof **inputColor);
}

The first malloc allocates memory for pictureHeight number of rows, the for loop allocates memory for each row with the size of pictureWidth.

The access is the same as the pointer to array method.

In these simplified pieces of code no error checks are performed, it's something you should do, namely checking malloc return values for errors.

Don't forget to free the memory when you're done with it:

For the first example:

free(inputColor);

For the second:

for (int y = 0; y < pictureHeight; y++)
{
    free(inputColor[y]);
}
free(inputColor);