Can you assign values to all elements in struct for a 2D array in C?

82 Views Asked by At

I want to make a grayscale filter so I have to assign the average of all 3 RGB values to each. I use a 2D array because this is a bitmap image and I'm filtering it by changing each pixel.

This is how the struct is defined (where BYTE is uint8_t):

typedef struct
{
    BYTE  rgbtBlue;
    BYTE  rgbtGreen;
    BYTE  rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;

Do I need to assign the value to each element of struct separately, like I did below, or is there a way to assign that value to all elements of the struct (since they are the same type) in that specific location in the array at once?

This is the code for the filtering function.

void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
    for (int i = 0; i < height; i++)
    {
        for (int j = 0 ; j < width; j++)
        {
            image[i][j].rgbtBlue = (image[i][j].rgbtBlue + image[i][j].rgbtRed + image[i][j].rgbtGreen)/3;
            image[i][j].rgbtGreen = (image[i][j].rgbtBlue + image[i][j].rgbtRed + image[i][j].rgbtGreen)/3;
            image[i][j].rgbtRed = (image[i][j].rgbtBlue + image[i][j].rgbtRed + image[i][j].rgbtGreen)/3;
        }
    }
    return;
}
2

There are 2 best solutions below

0
Eric Postpischil On BEST ANSWER

You can do it with a compound literal:

RGBTRIPLE x = image[i][j];  // Use temporary to reduce repetition.
BYTE t = (x.rgbtBlue + x.rgbtRed + x.rgbtGreen)/3;
image[i][j] = (RGBTRIPLE) { t, t, t };
2
Adrian Mole On

You can certainly avoid making the calculation three times on each loop. Two obvious ways to do this are:

(1) Chain the assignments (note that expressions like a = b = 3; are valid C and the = operator associates right-to-left);

void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            image[i][j].rgbtBlue = image[i][j].rgbtGreen = image[i][j].rgbtRed =
                (image[i][j].rgbtBlue + image[i][j].rgbtRed + image[i][j].rgbtGreen) / 3;
        }
    }
    return;
}

(2) Calculate that 'gray' value and assign that to the array element (in one go) using a compound literal constructed from that calculated value:

void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            BYTE gray = (image[i][j].rgbtBlue + image[i][j].rgbtRed + image[i][j].rgbtGreen) / 3;
            image[i][j] = (RGBTRIPLE){ gray, gray, gray };
        }
    }
    return;
}

Whether or not either of the above actually constitutes an improvement is subjective (and a good compiler will likely generate the same code in both cases). However, for more complex situations, these techniques can make your code clearer and its purpose easier for a reader to understand.


Note also that, as pointed out in the comments, the above two examples will assign the same value to each of the three components of the image[i][j] element. In your posted code, the second and third recalculations use one or two values that will have been modified by the previous line(s).