multiArray и multiArray и & multiArray одинаково?

На 6-й строке вместо multiArray [0], когда я пишу multiArray, программа все еще работает. Не понимаю, почему. Я думал, что multiArray является указателем на multiArray [0], который является указателем на multiArray [0] [0]. Таким образом, multiArray является указателем на указатель. multiArray [0] – указатель на 4-элементный массив int. Таким образом, кажется, что multiArray и multiArray [0] должны быть разными. Но в нижнем коде обе работают. Функция печати, которую я написал, ожидает указатель на 4-элементный массив int. Поэтому должен работать только multiArray [0], и multiArray не должен работать. Но оба работают. Не понял этого.

#include  void printArr(int(*ptr)[4]); int i, k; int main(void){ int multiArray[3][4] = { { 1, 5, 2, 4 }, { 0, 6, 3, 14 }, { 132, 4, 22, 5 } }; int(*point)[4] = multiArray[0]; for (k = 0; k < 3; k++) { printArr(point++); } getchar(); } void printArr(int(*ptr)[4]){ int *temp = (int *)ptr; for (i = 0; i < 4; i++) { printf("%d ", *temp); temp++; } puts("\n"); } 

Кто-то еще написал «Многомерные массивы – это синтаксический сахар для 1-D массивов».

Это похоже на то, что int – это просто синтаксический сахар для unsigned char[4] . Вы могли бы избавиться от выражений типа 4 + 5 и получить тот же результат, манипулируя массивами из 4 байтов.

Вы даже можете сказать, что C является просто синтаксическим сахаром для сценария Universal Turing Machine, если вы хотите принять эту концепцию немного дальше.

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

Двигаясь дальше, способ, которым C организует то, что мы называем многомерным массивом, состоит в том, чтобы сказать: «Массивы могут иметь только одно измерение, но тип элемента сам может быть другим массивом». Мы говорим «multidimensional array» как вопрос удобства, но синтаксис и система типов фактически отражают одномерный характер массива.

Таким образом, int multiArray[3][4] представляет собой массив из 3 элементов. Каждый из этих элементов представляет собой массив из 4 ints .

В памяти элементы массива хранятся смежно – независимо от типа элемента. Таким образом, макет памяти представляет собой массив из 4 int , за которым сразу следует еще один массив из 4 int и, наконец, еще один массив из 4 int .

В памяти имеется 12 смежных int , а в системе типа C они группируются в 3 группы по 4.

Вы заметите, что первый int из 12 также является первым int первой группы из 4. Вот почему мы находим, что если мы спросим: «Каково местоположение памяти первого int?», «Каково место памяти первой группы из 4-х int? »и« Что такое ячейка памяти всего блока из 12 ints? », мы получаем один и тот же ответ каждый раз. (В C считается, что местоположение памяти многобайтового объекта начинается с местоположения его первого байта).

Теперь поговорим о синтаксисе и представлении указателя. В C указатель указывает, где в памяти может быть найден объект. Для этого есть два аспекта: расположение памяти объекта и тип объекта. (Размер объекта является следствием типа).

Некоторые презентации сосредоточены только на первом из них, они скажут такие вещи, как «Указатель – это просто число». Но это забывает о типе информации, которая является важной частью указателя.

Когда вы печатаете указатель с %p , вы теряете информацию о типе. Вы просто кладете место в память первого байта. Таким образом, все они выглядят одинаково, несмотря на то, что три указателя указывают на объекты разного размера (которые перекрывают друг друга, как куклы матрушха).

В большинстве реализаций C информация о типе вычисляется во время компиляции, поэтому, если вы попытаетесь понять C, сравнивая исходный код с ассемблерным кодом (некоторые это делают), вы видите только часть местоположения памяти в указателе. Это может привести к недоразумению, если вы забудете, что информация о типе также имеет решающее значение.

Сноска: все это не зависит от пары синтаксических причуд, которые имеют C; которые вызвали много путаницы на протяжении многих лет (но иногда также полезны). Выражение x является ярлыком для &x[0] если x является массивом, за исключением случаев, когда он используется как операнд & или sizeof . (В противном случае это будет рекурсивное определение!). Вторая особенность заключается в том, что если вы пишете то, что выглядит как объявление объявления массива в списке формальных параметров функции, на самом деле вы написали декларатор указателя. Я еще раз подчеркиваю, что это всего лишь синтаксические странности, они не говорят ничего фундаментального о природе массивов и указателей, что на самом деле не так сложно. Язык также будет работать без обоих этих причуд.

Многомерные массивы var_t arr[size_y][size_x] предоставляют средства для объявления и доступа к элементам массива (памяти) удобным образом. Но все многомерные массивы являются внутренне непрерывными блоками памяти.

Вы можете сказать, что arr[y][x] = arr[y*cols+x] .

В терминах уровня указателя указатели multiArray и multiArray[0] одинаковы, они являются int* – хотя формальный тип для arr будет int (*)[2] . Используя этот тип, вы сможете воспользоваться всеми механиками указателя (++ на таком указателе будет перемещать адрес на 8 байтов, а не на 4).

Попробуй это:

 void t1(int* param) { printf("t1: %d\n", *param); } void t2(int** param) { printf("t2: %d\n", **param); } int main(void) { int arr[2][2] = { { 1, 2 } , { 3, 4 } }; t1(arr); // works ok t1(arr[0]); // works ok t2(arr); // seg fault t2(arr[0]); } 

int(*point)[4] = multiArray[0];

Это работает, потому что и multiArray[0] и multiArray указывают на тот же адрес, адрес первого элемента массива: multiArray[0][0] .

Однако в этом случае вы можете получить предупреждение от компилятора, потому что тип multiArray[0] – это int* while point is int [4]* (указатель на массив из 4 целых чисел).