#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));
}