Подтвердить что ты не робот

Многомерные массивы в C: они зубчатые?

Простой вопрос о языке программирования C (ANSI-C):

Являются ли многомерные массивы в C зубчатыми?

Я имею в виду - мы говорим о "массиве массивов" (один массив указателей на другие адреса в памяти), или это просто "длинный одномерный массив" (который сохраняется последовательно в памяти)?

Что меня беспокоит, так это то, что я уверен, что:

matrix[i][j] эквивалентно * ( * (matrix + i) + j)

4b9b3361

Ответ 1

Многомерный массив в C смежный. Следующее:

int m[4][5];

состоит из 4 int[5], расположенных рядом друг с другом в памяти.

Массив указателей:

int *m[4];

зазубрен. Каждый указатель может указать (первый элемент) отдельный массив разной длины.

m[i][j] эквивалентен *(*(m+i)+j). См. стандарт C11, раздел 6.5.2.1:

Определение индексного оператора [] состоит в том, что E1 [E2] идентичен (* ((E1) + (E2)))

Таким образом, m[i][j] эквивалентно (*(m+i))[j], что эквивалентно *(*(m+i)+j).

Эта эквивалентность существует, потому что в большинстве контекстов выражения типа массива распадаются на указатели на их первый элемент (стандарт C11, 6.3.2.1). m[i][j] интерпретируется как:

  • m - массив массивов, поэтому он распадается на указатель на m[0], первый подмассив.
  • m+i является указателем на i -ный подмассив m.
  • m[i] эквивалентен *(m+i), разыменовывая указатель на i -ный подмассив m. Поскольку это выражение типа массива, оно распадается на указатель на m[i][0].
  • m[i][j] эквивалентен *(*(m+i)+j), разыменовывая указатель на j -й элемент i -го подмассива <<29 > .

Обратите внимание, что указатели на массивы отличаются от указателей на их первый элемент. m+i - указатель на массив; это не выражение типа массива, и оно не распадается, будь то указатель на указатель или на любой другой тип.

Ответ 2

Последовательная область памяти:

int arr[N][M];

Непересекающаяся область памяти:

int** arr = malloc(N*sizeof(int*));
for (int i=0; i<N; i++)
    arr[i] = malloc(M*sizeof(int));

Вы можете использовать arr как 2-мерный массив (например, arr[1][2] = 3) в обоих случаях. Но вы можете безопасно применять большие операции копирования, такие как memset(arr,0,N*M*sizeof(int)), только в первом случае.

Ответ 3

Это будет зависеть.

Многомерные массивы в C последовательно расположены.

Вы можете создавать зубчатые массивы, если хотите использовать указатели.

Ответ 4

Если вы объявляете многомерный массив, вы получаете "длинный одномерный массив" (который сохраняется последовательно в памяти).

Если вы объявляете указатель на указатель (на указатель....), вы получаете массивы массивов.

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

Ответ 5

Массив или массивы, такие как int matrix[A][B], не зазубрены, так как каждый элемент matrix является array of B int.

Вы хотите знать, что результат *(*(matrix+i)+j) есть и сравнить его с результатом matrix[i][j].

Так как тип matrix равен array of A array of B int, то выражение matrix+i является указателем, указывающим на i th array of B int of matrix, а его тип int (*)[B]. Разыменование этого выражения приводит к array of B int. Выражение *(matrix+i)+j) приводит к указателю на j th int этого массива. Выражение разыгрыша этого выражения приводит к int. Это эквивалентно выражению matrix[i][j].

Массив указателей, таких как int *matrix[A], может быть неровным, так как каждый элемент matrix может указывать на распределение по разному.

Ответ 6

Вы правы, что matrix[i][j] эквивалентно *(*(matrix + i) + j), так как arr[i] эквивалентен *(arr + i). Однако имейте в виду, что если arr объявлен как

int arr[64];

то любая ссылка на arr может быть неявно преобразована в &arr[0], то есть указатель на первый элемент. То же самое происходит с массивами массивов:

int matrix[8][8];

Здесь matrix имеет тип int[8][8], который автоматически преобразуется в int (*)[8], когда вы добавляете к нему целое число, как в matrix + i. Тогда *(matrix + i) имеет тип int[8], который снова преобразуется в int *, когда вы добавляете j, поэтому *(matrix + i) + j имеет тип int *, поэтому *(*(matrix + i) + j) имеет тип int, как ожидалось.

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

Итак, если вы выделяете массивы таких массивов, как указано выше (int matrix[8][8];), тогда все элементы последовательно хранятся в памяти.