Home > Mobile >  Dynamically allocate 2-dimensional structure array in C
Dynamically allocate 2-dimensional structure array in C

Time:08-11

I have been trying to create an edges filter as per CS50 problem set 4. I have seen several solutions, however I would like to know if my approach can work. I'm trying to expand the input image by a black border of one pixel width. For this I want to expand my two-dimensional RGBTRIPLE structure by one pixel on either side. I am setting all values of RGB to 0 (aka black) in the first line and then copy the original image into the temporary structure, substituting all except the border values with the respective colours.

I am defining a variable-length two-dimensional structure RGBTRIPLE which contains three values of the datatype BYTE:

RGBTRIPLE temp[height 2][width 2] = {};

I'm getting the error message that because of the variable length it may not have been initialized, which I understand. I have seen several solutions using pointers and malloc, which I hopefully implemented correctly in the first line. I have been trying to connect the RGBTRIPLE to the pointer as per the following two lines:

RGBTRIPLE *ptr = (RGBTRIPLE *)malloc((height 2)*(width 2)*sizeof(RGBTRIPLE));
RGBTRIPLE temp[height 2][width 2] = &ptr;
temp[height 2][width 2] = {0};

Setting all the values to zero here does also not work, but that's another issue.

I want to use the original RGBTRIPLE in a for-loop and I cannot get this to work. All examples I have seen use the pointers afterwards to add any information. Is there any way to define the RGBTRIPLE using malloc so that I can afterwards use it in code as a "normal" element of the structure as seen with temp[][]:

for(int i = 0; i < height; i  )
{
    for(int j = 0; j < width; j  )
    {
        temp[i 1][j 1] = image[i][j];
    }
}

for(int i = 1; i <= height; i  )
{
    for(int j = 1; j <= width; j  )
    {
        int counter = 0;
        float gxr, gxb, gxg, gyr, gyb, gyg = 0;

        //right pixel
        gxb  = (2*temp[i][j 1].rgbtBlue);
        gxg  = (2*temp[i][j 1].rgbtGreen);
        gxr  = (2*temp[i][j 1].rgbtRed);

etc. for all surrounding pixels.

Any help is appreciated.

CodePudding user response:

You might initialize as in the following sample code.

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

typedef unsigned char BYTE;

typedef struct tagRGBTRIPLE
{
    BYTE rgbtBlue;
    BYTE rgbtGreen;
    BYTE rgbtRed;
} RGBTRIPLE;

int main()
{
    int height = 400;
    int width  = 600;

    RGBTRIPLE img[height][width];
    RGBTRIPLE temp[height 2][width 2];

    for (int i = 0; i < height; i  )                /* Build a sample image file */
    {
        for (int j = 0; j < width; j  )
        {
            img[i][j].rgbtRed   = 68;
            img[i][j].rgbtGreen = 188;
            img[i][j].rgbtBlue  = 32;
        }
    }

    for (int i = 0; i < (height   2); i  )          /* Initialize the temporary RGBTRIPLE structure*/
        for (int j = 0; j < (width   2); j  )
        {
            temp[i][j].rgbtRed   = 0;
            temp[i][j].rgbtGreen = 0;
            temp[i][j].rgbtBlue  = 0;
        }

    for(int i = 0; i < height; i  )                 /* Imported code from the issue */
    {
        for(int j = 0; j < width; j  )
        {
            temp[i 1][j 1] = img[i][j];
        }
    }

    for(int i = 0; i <= (height   2); i  )          /* Right and left edges*/
    {
        float gxr = 0, gxb = 0, gxg = 0;

        temp[i][0].rgbtRed   = gxr;
        temp[i][0].rgbtGreen = gxg;
        temp[i][0].rgbtBlue  = gxb;
        temp[i][width   1].rgbtRed   = gxr;
        temp[i][width   1].rgbtGreen = gxg;
        temp[i][width   1].rgbtBlue  = gxb;
    }

    for(int i = 0; i <= (width   2); i  )           /* Top and bottom edges */
    {
        float gyr = 0, gyb = 0, gyg = 0;

        temp[0][i].rgbtRed   = gyr;
        temp[0][i].rgbtGreen = gyg;
        temp[0][i].rgbtBlue  = gyb;
        temp[height   1][i].rgbtRed   = gyr;
        temp[height   1][i].rgbtGreen = gyg;
        temp[height   1][i].rgbtBlue  = gyb;
    }

    /* See what we have at a pixel point */

    printf("Top edge RGBTRIPLE %d, %d, %d \n", temp[0][144].rgbtRed, temp[0][144].rgbtGreen, temp[0][144].rgbtBlue);
    printf("Left edge RGBTRIPLE %d, %d, %d \n", temp[144][0].rgbtRed, temp[144][0].rgbtGreen, temp[144][0].rgbtBlue);
    printf("RGBTRIPLE within image %d, %d, %d \n", temp[144][144].rgbtRed, temp[144][144].rgbtGreen, temp[144][144].rgbtBlue);

    return 0;
}

C does not really provide a simple way to initialize tuples so you probably would need "for" loops to do this. Experiment with this scenario and see if it applies to the spirit of your project.

CodePudding user response:

Some issues:

Use mem...() where possible.

To zero byte fill an entire variable length array:

// RGBTRIPLE temp[height 2][width 2] = {};
RGBTRIPLE temp[height 2][width 2];
memset(temp, 0, sizeof temp);

I am setting all values of RGB to 0 (aka black) in the first line and then copy the original image into the temporary structure, substituting all except the border values with the respective colours.

Alternative:

// Given image[][] is a 2D array 
for(int i = 0; i < height; i  ) {
  memcpy(temp[i 1], image[i], sizeof image[i]);
}

Initialize properly

float gxr, gxb, gxg, gyr, gyb, gyg = 0; only initializes gyg.

float gxr = 0;
float gxb = 0;
...
float gyg = 0;

Advanced: int math vs. size_t math

int*int*size_t may overflow int*int where size_t*int*int does not.

Cast not needed in C.

Size to the referenced object, not the type.

// RGBTRIPLE *ptr = (RGBTRIPLE *)malloc((height 2)*(width 2)*sizeof(RGBTRIPLE));
RGBTRIPLE *ptr = malloc(sizeof ptr[0] * (height 2) * (width 2));
  • Related