4

What does the following line do, step by step (filter.c L:78)

RGBTRIPLE(*image)[width] = calloc(height, width * sizeof(RGBTRIPLE));

I am most confused by the syntax of

RGBTRIPLE(*image)[width]

What i believe I understand

  • RGBTRIPLE is a struct
  • image will be the variable name, which will be a pointer to a location in memory where there will be be the first element of an array of RGBTRIPLE's, which is the first location in the block allocated by calloc
  • the array pointed to be image will be [width] elements long
  • calloc is setting aside a block of memory initialized to zero, that is == the size of RGBTRIPLE's in a width x height image

What I am confused about

  • What are the parentheses doing?
  • Why are there no spaces?
  • Why is width being used, and not height (isn't each element in the array a row in the image, not a column?)
4

RGBTRIPLE(*image)[width] means variable image is a pointer to an array of length width of RGBTRIPLE.

RGBTRIPLE *image[width] means variable image is an array of width pointers to RGBTRIPLE.

The parentheses couple the * closer to the variable, and change the meaning.

Spaces are often optional, style guides want them in a specific way or another.

width is used because of how those 2D arrays work.

It's width because that corresponds to the second index. image[i][j] will look at the memory address of image, add i times the size of RGBTRIPLE[width], and to the result will add j times the size of RGBTRIPLE.

#include <stdio.h>

int main() {
    int array[23][42];
    printf("size of array:   %zu\n", sizeof(  array));
    printf("size of row:     %zu\n", sizeof( *array));
    printf("size of element: %zu\n", sizeof(**array));
    return 0;
}

And for the fun of it, &array, &array[0], and &array[0][0] will report the same memory address.

5
  • Thanks, that helps a bit.I guess it's the parentheses that are throwing me. I understand the end functionality that you've described, but how exactly those parentheses are achieving it (changing the meaning as you say) is a bit unclear to me. I suppose I need to read up on c syntax more, and wrap my head around where the first index of the image array is coming from then.
    – drl
    Mar 18 '20 at 14:08
  • The parentheses are there for changing the order in which the various modifiers are applied, and therefore what they are applied to. It's the same as using parentheses in calculations. a + b * c is different from (a + b) * c. The * is stronger than the +, so we have to add parentheses if we want to change the order.
    – Blauelf
    Mar 18 '20 at 15:40
  • Hello, I am still confused about how "RGBTRIPLE(*image)[width] means variable image is a pointer to an array of length width of RGBTRIPLE." How does the parenthesis change its meaning? Jul 27 '20 at 3:45
  • And also, is it the same to declare it as: RGBTRIPLE **image= calloc(height, width * sizeof(RGBTRIPLE)); Jul 27 '20 at 3:55
  • @ChenShujuan It's read from inside to outside, from right to left. Without the parentheses, it would be an array of width pointers to a value of type RGBTRIPLE, not a pointer to an array of width elements of type RGBTRIPLE. And your second question, RGBTRIPLE[width] is different from a RGBTRIPLE*. When passed around to other functions, it would "decay" to such pointer (containing the memory address of the first element). but the RGBTRIPLE[width] stores actual RGBTRIPLEs, while the RGBTRIPLE* is just a pointer, storing a memory address.
    – Blauelf
    Jul 28 '20 at 10:08
1

What are the parentheses doing?

As Blauelf explained, they are changing order of operations. I didn't full grasp why this was needed though until trying to compile without them.

filter.c:78:15: error: variable-sized object may not be initialized
RGBTRIPLE*image[width] = calloc(height, width * sizeof(RGBTRIPLE));

They ensure *image creates a ptr called image, and [width] is treated separately as an array dimension. Still don't fully understand what is being attempted without them, but I now understand their necessity...

My main point of confusion was that I understood this works totally fine...

int n = 4;
int *d_arr = malloc(sizeof(int) * n);
for (int i = 0; i < n; i++)
{
  d_arr[i] = i;
  printf("1d: [%i] is %i\n", i, d_arr[i]);
}

So I assumed that this would also work fine...

  int n = 4;
  int *dd_arr = malloc(sizeof(int) * n * n); 
  for (int i = 0; i < n; i++)
  {
    for (int j = 0; j < n; j++)
    {   
      dd_arr[i][j] = i + j;
      printf("2d: [%i][%i] is %i\n", i, j, dd_arr[i][j]);
    }   
  }
}

But it does not, and won't compile with

2d_arr.c:12:16: error: subscripted value is not an array, pointer, or vector
      dd_arr[i][j] = i + j;
      ~~~~~~~~~^~
2d_arr.c:13:53: error: subscripted value is not an array, pointer, or vector
      printf("2d: [%i][%j] is %i\n", i, j, dd_arr[i][j]);

You have to have line two as

int (*dd_arr)[n] = malloc(sizeof(int) * n * n);

Which brings me to my understanding of the following...

Why is width being used, and not height (isn't each element in the array a row in the image, not a column?)

Best as I understand it, *dd_arr can be treated like an array out of the box, but since a 2d array is really an array OF arrays, you need to let the compiler know this so you can operate on that nested level (or another way, "image" is a pointer to an array that contains "width" number of arrays of RGBTRIPLES)

^^ Is that right?

And in the original question it's width not height, because height is the length of the outermost array implied by the *image, which doesn't need to be specified.

Why are there no spaces?

As Blauelf explained, not functional, only stylistic choice (albeit confusing to me at the time).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .