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 являются строкой и приращения адреса столбца, соответственно.