2D-массив против массива массивов
В чем разница между 2D-массивом и массивом массивов?
Я прочитал комментарии, такие как @Dave's, которые, по-видимому, различают эти два.
Это прерывается, если он использует 2d-массивы или типы указателя-массива, а не массив массивов. - Дэйв
Я всегда думал, что оба упомянуты:
int arr_arr[][];
EDIT: @FutureReader, вы можете захотеть увидеть Как использовать массивы на С++?
Ответы
Ответ 1
2-мерный массив по определению представляет собой массив массивов.
То, что говорил Дейв, заключается в том, что в этом контексте существует различная семантика между определением 2D-массива следующим образом:
int x[][];
int *x[];
или это:
int **x;
Ответ 2
Здесь есть четыре разных понятия.
- Двумерный массив:
int arr[][]
. Он не может быть изменен в любом направлении и является смежным. Индексирование - это то же самое, что и ((int*)arr)[y*w + x]
. Должно быть назначено статически.
- Указатель на массив:
int (*arr)[]
. Он может быть изменен только для добавления нескольких строк и является смежным. Индексирование - это то же самое, что и ((int*)arr)[y*w + x]
. Должно выделяться динамически, но может быть освобождено free(x)
;
- Указатель на указатель:
int **arr
. Он может быть изменен в любом направлении и не обязательно является квадратным. Обычно выделяемое динамически, не обязательно смежное и освобождение зависит от его конструкции. Индексация совпадает с *(*(arr+y)+x)
.
- Массив указателей:
int *arr[]
. Он может быть изменен только для добавления большего количества столбцов и не обязательно является квадратным. Изменение размера и освобождение также зависит от конструкции. Индексация совпадает с *(*(arr+y)+x)
.
Каждый из них может быть использован arr[y][x]
, что приводит к путанице.
Ответ 3
Ответ здесь немного более тонкий.
Массив массивов определяется как таковой:
int array2[][];
Определены типы указателя на массив:
int (*array2)[];
Определяется тип массива-указателя:
int* array2[];
Компилятор рассматривает оба этих вопроса несколько иначе, и действительно есть еще один вариант:
int** array2;
Многие люди учат, что эти три идентичны, но если вы знаете больше о компиляторах, вы наверняка узнаете, что разница небольшая, но она есть. Многие программы будут выполняться, если вы замените один на другой, но на уровне компилятора и ASM вещи НЕ совпадают. Учебник по компиляторам C должен предоставить гораздо более глубокий ответ.
Кроме того, если кто-то заинтересован в реализации 2D-массива, в зависимости от ситуации существует несколько методов, которые различаются по эффективности. Вы можете сопоставить 2D-массив с массивом 1D, который обеспечивает пространственную локальность при работе с линеаризованными данными. Вы можете использовать массив массивов, если хотите упростить программирование, и если вам нужно манипулировать строками/столбцами отдельно. Существуют определенные заблокированные типы и другие причудливые проекты, которые являются интеллектуальными, но редко вам нужно знать реализацию, если вы пользователь.
Надеюсь, я помог!
Ответ 4
Ниже представлен 2D-массив, который можно назвать массивом массивов:
int AoA[10][10];
Ниже приведен указатель на указатель, который был настроен для работы в виде 2D-массива:
int **P2P = malloc(10 * sizeof *P2P);
if(!P2P) exit(1);
for(size_t i = 0; i < 10; i++)
{
P2P[i] = malloc(10 * sizeof **P2P);
if(!P2P[i])
{
for(; i > 0; i--)
free(P2P[i - 1]);
free(P2P);
}
}
Оба доступны через AoA[x][y]
или P2P[x][y]
, но они несовместимы. В частности, P2P = AoA
- это то, что новички иногда ожидают работать, но не будет - P2P
ожидает указать указатели, но когда AoA
распадается на указатель, это указатель на массив, в частности int (*)[10]
, который не является int **
, который должен быть P2P
.
Ответ 5
2d массив может включать следующее:
int x[width * height]; // access: x[x + y * height]\
Из Википедии:
Для двумерного массива элемент с индексами i, j будет иметь адрес B + c · я + d · j, где коэффициенты c и d являются строкой и приращения адреса столбца, соответственно.