запутался в синтаксисе указателя при определении типа в C

#arrays #c #pointers #pointer-to-array

#массивы #c #указатели #указатель на массив

Вопрос:

В некотором стартовом коде мы имеем:

  /**
 * 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;
  

и в нашей основной программе мы имеем:

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

Меня смущает (* изображение)

Если бы я должен был определить указатель на RGBTRIPLE, я подумал, что использовал бы:

 RGBTRIPLE *image[width] = ....
  

Это то же самое, что:

 RGBTRIPLE(*image)[width] = ....   ?
  

Комментарии:

1. С тех пор я не помечен struts … вообще не связано.

Ответ №1:

 RGBTRIPLE *image[width]; 
  

Является массивом указателей на RGBTRIPLE , этот массив будет иметь width количество элементов. Каждый указатель в этом массиве способен указывать на RGBTRIPLE объект, что позволяет получить 2D-массив, когда у вас есть несколько таких объектов в строке.

Распределение более запутанное, потому что вам нужно было бы выделить массив самих указателей, а затем каждую строку, на которую указывал бы каждый указатель, и позже освободить память в обратном порядке.


 RGBTRIPLE(*image)[width];
  

Является указателем на массив RGBTRIPLE , этот массив должен иметь width количество элементов, в этом случае вы можете использовать его для указания на 2D-массив с любым количеством строк при условии, что в нем есть width количество столбцов.

Это лучший способ внедрения 2D-массива, потому что это облегчает выделение и освобождение.

Это работает, позволяя перемещать указатель в блоках width размером в байты путем его увеличения, на практике это позволяет вам «перейти» к следующей строке, увеличив указатель один раз.

Например, массив из 6 width и 2 из 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]
  

Выражение:

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

могло бы быть лучше, я бы использовал более безопасный метод:

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

Комментарии:

1. это очень полезно, спасибо. Как бы мне распечатать значение image [0][4] с помощью printf? Когда я пытаюсь, он продолжает говорить, что мой тип имеет RGBTRIPLE (который представляет собой набор из 3 байт) и что дополнительный спецификатор формата неверен

2. @DCR вам нужно ссылаться на каждый элемент структуры, например image[0][4].rgbtBlue

3. «… но не указана высота» — это вводит в заблуждение. Это указатель на массив с width элементами. Как и в случае с любым указателем, он также может указывать на первый элемент массива (в данном случае массива из width троек RGB).

4. @anastaciu просто чтобы убедиться, что я это понимаю, во втором примере RGBTRIPLE(*image)[width] кажется, что я мог бы сделать то же самое с RGBTRIPLE image[width], а затем выполнить RGBTRIPLE * ip = amp;image. Это правильно?

5. @DCR у вас мог бы быть RGBTRIPLE image[width]; и RGBTRIPLE *ip = image; , image распадется на указатель, вам не понадобится amp; оператор, но он отличается от (*image)[width] , первый — это указатель на RGBTRIPLE , и вы можете заставить его указывать на любой элемент в массиве объектов этого типа, последний — это указатель на массив width элементов, я должен указывать не на отдельный элемент, а на массив width элементов. Разница в именовании кажется незначительной, но это не так, это делает невозможным использование первого для эмуляции 2D-массива, ip[0][4] это незаконно, image[0][4] нет.

Ответ №2:

Это не одно и то же.

 RGBTRIPLE *image[width]
  

Это обозначает массив размера, width элементы которого имеют тип RGBTRIPLE * , то есть это массив указателей.

 RGBTRIPLE(*image)[width]
  

Это указатель на массив размера, width члены которого имеют тип RGBTRIPLE .

Оба могут использоваться для реализации 2D-массива, но по-разному. Если бы вы использовали предыдущее объявление, вам пришлось бы выделить дополнительное измерение следующим образом:

 int i;
for (i=0; i<width; i  ) {
    image[i] = calloc(height, sizeof(RGBTRIPLE));
}