Как многомерные массивы отформатированы в памяти?

В C я знаю, что могу динамично выделить двухмерную антенную решетку на "куче" с помощью следующего кода:

int** someNumbers = malloc(arrayRows*sizeof(int*));

for (i = 0; i < arrayRows; i++) {
    someNumbers[i] = malloc(arrayColumns*sizeof(int));
}

Очевидно, это на самом деле создает одномерный массив указателей на набор отдельных одномерных массивов целых чисел, и "Система" может выяснить то, что я имею в виду, когда я прошу:

someNumbers[4][2];

Но когда я статически объявляю 2D массив, как в следующей строке...:

int someNumbers[ARRAY_ROWS][ARRAY_COLUMNS];

... подобная структура становится созданной на стеке или это имеет другую форму полностью? (т.е. действительно ли это 1D массив указателей? В противном случае, что это, и как делают ссылки на него вычислены?)

Кроме того, когда я сказал, "Система", что на самом деле ответственно за понимание этого? Ядро? Или компилятор C улаживает его при компиляции?

165
задан Chris Cooper 6 May 2013 в 00:03
поделиться

3 ответа

Статический двумерный массив выглядит как массив массивов - он просто расположен в памяти непрерывно. Массивы - это не то же самое, что указатели, но поскольку вы можете часто использовать их в значительной степени взаимозаменяемо, это иногда может сбивать с толку. Тем не менее, компилятор отслеживает все правильно, что делает все правильно выстраиваемым. Вы должны быть осторожны со статическими 2D-массивами, как вы упомянули, поскольку, если вы попытаетесь передать один из функций, принимающих параметр int ** , произойдут плохие вещи.Вот краткий пример:

int array1[3][2] = {{0, 1}, {2, 3}, {4, 5}};

В памяти выглядит так:

0 1 2 3 4 5

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

int array2[6] = { 0, 1, 2, 3, 4, 5 };

Но если вы попытаетесь передать array1 этой функции:

void function1(int **a);

you ' я получу предупреждение (и приложение не сможет правильно получить доступ к массиву):

warning: passing argument 1 of ‘function1’ from incompatible pointer type

Потому что 2D-массив - это не то же самое, что int ** . Автоматическое преобразование массива в указатель идет, так сказать, «на один уровень в глубину». Вам нужно объявить функцию как:

void function2(int a[][2]);

или

void function2(int a[3][2]);

, чтобы все было хорошо.

Эта же концепция распространяется на n -мерные массивы. Однако использование преимуществ такого рода забавных дел в вашем приложении, как правило, только усложняет понимание. Так что будьте осторожны.

129
ответ дан 23 November 2019 в 21:09
поделиться

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

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

В случае массива malloc, «Система» будет реализатором malloc (обычно это ядро). Все, что компилятор выделит, - это базовый указатель.

Компилятор всегда будет обрабатывать типы так, как они объявлены, за исключением примера, приведенного Карлом, где он может определить взаимозаменяемое использование. Вот почему, если вы передаете [] [] функции, она должна предполагать, что это статически выделенная квартира, где ** считается указателем на указатель.

5
ответ дан 23 November 2019 в 21:09
поделиться

Ответ основан на идее, что C на самом деле не имеет 2D-массивов - у него есть массивы-массивы. Когда вы объявляете это:

int someNumbers[4][2];

Вы запрашиваете someNumbers как массив из 4 элементов, где каждый элемент этого массива имеет тип int [2] (который сам по себе массив из 2 int s).

Другая часть загадки состоит в том, что массивы всегда располагаются в памяти непрерывно. Если вы запросите:

sometype_t array[4];

, то это всегда будет выглядеть так:

| sometype_t | sometype_t | sometype_t | sometype_t |

(4 sometype_t объектов, расположенных рядом друг с другом, без пробелов между ними). Итак, в вашем массиве массивов someNumbers он будет выглядеть так:

| int [2]    | int [2]    | int [2]    | int [2]    |

И каждый элемент int [2] сам по себе является массивом, который выглядит следующим образом:

| int        | int        |

В общем, вы получите следующее:

| int | int  | int | int  | int | int  | int | int  |
79
ответ дан 23 November 2019 в 21:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: