1

In some starter code we have:

 /**
 * RGBTRIPLE
 *
 * This structure describes a color consisting of relative intensities of
 * red, green, and blue.   
 *
 * Adapted from http://msdn.microsoft.com/en-us/library/aa922590.aspx.
 */
 typedef struct
{
    BYTE  rgbtBlue;
    BYTE  rgbtGreen;
    BYTE  rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;

and in our main program we have:

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

I'm confused about (*image)

If I was to define a pointer to a RGBTRIPLE I thought I would use:

RGBTRIPLE *image[width] = ....

Is that the same as:

RGBTRIPLE(*image)[width] = ....   ?
anastaciu
  • 23,467
  • 7
  • 28
  • 53
DCR
  • 14,737
  • 12
  • 52
  • 115

2 Answers2

3
RGBTRIPLE *image[width]; 

Is an array of pointers to RGBTRIPLE, this array will have width number of elements. Each pointer in this array is capable of pointing to a RGBTRIPLE object, that makes it possible to have a 2D array when you have several of these objects per row.

The allocation is messier because you would need to allocate the array of pointers themselves and then each row for which each pointer would be pointing to, and later deallocate the memory in reverse order.


RGBTRIPLE(*image)[width];

Is a pointer to array of RGBTRIPLE, this array must have width number of elements, that being the case you can use it to point to a 2D array with any number of rows as long as it has width number of columns.

This is a better way of implenting a 2D array because it facilitates the allocation and deallocation.

This works by allowing it to move the pointer in blocks of width size of bytes by incrementing it, in practice it let's you "jump" to the next row by incrementing the pointer once.

For example, an array of 6 of width and 2 of height:

             +-----------+
image[0] ->  |0|1|2|3|4|5|
             +-----------+
             |5|4|3|2|1|0|
             +-----------+
                      
              
                      +-> image[0][4]
                      |
             +-----------+
             |0|1|2|3|4|5|
             +-----------+
image[1] ->  |5|4|3|2|1|0|
             +-----------+
                      |
                      +-> image[1][4]

The expression:

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

could be better, I would use a safer method:

RGBTRIPLE(*image)[width] = calloc(height, sizeof *image);
anastaciu
  • 23,467
  • 7
  • 28
  • 53
  • 1
    this is very helpful, thank you. How would I print out the value of image[0][4] using printf? When I try it keeps saying my type is of RGBTRIPLE (which is a collection of 3 bytes) and that more format specifier is incorrect – DCR Aug 23 '20 at 23:31
  • @DCR you need to reference each member of the struct, for example `image[0][4].rgbtBlue` – anastaciu Aug 23 '20 at 23:34
  • 1
    "...but unspecified height" -- that's misleading. It is a pointer to an array with `width` elements. Just as with any pointer, it can also point to the first element of an array (an array of arrays of `width` RGB triples in this case). – Ulrich Eckhardt Aug 24 '20 at 14:30
  • @anastaciu just to make sure I understand this, in the second example RGBTRIPLE(*image)[width] it seems that I could do the same thing with RGBTRIPLE image[width] and then do RGBTRIPLE * ip = &image. Is that correct? – DCR Aug 24 '20 at 16:27
  • @DCR you could have `RGBTRIPLE image[width];` and `RGBTRIPLE *ip = image;`, `image` will decay to pointer, you won't need `&` operator, but it's different from `(*image)[width]`, the first is a pointer to `RGBTRIPLE` and you can make it point to any element in an array of objects of this type, the latter is a pointer to an array of `width`elements, i's not to point to a single element but to an array of `width`elements. The difference in naming seems subtle but it's not, it makes it impossible for you to use the first to emulate a 2D array, `ip[0][4]` is illegal, `image[0][4]` is not. – anastaciu Aug 24 '20 at 17:39
  • @DCR these are confusing concepts at first, but they will become clearer, the comment section is not the best place to explain all the details, but you could formulate a good question with this doubt. There is [this thread](https://stackoverflow.com/q/24104482/6865932) which can clear some of your doubts. – anastaciu Aug 24 '20 at 17:58
1

These are not the same.

RGBTRIPLE *image[width]

This denotes an array of size width whose elements are of type RGBTRIPLE *, i.e. it is an array of pointers.

RGBTRIPLE(*image)[width]

This is a pointer to an array of size width whose members are of type RGBTRIPLE.

Both can be used to implements a 2D array, but in different ways. If you used the former declaration, you would have to allocate the extra dimension as follows:

int i;
for (i=0; i<width; i++) {
    image[i] = calloc(height, sizeof(RGBTRIPLE));
}
dbush
  • 205,898
  • 23
  • 218
  • 273