В чем разница между int * x [n] [m] и int (* x) [n] [m]?
Как я вижу, int *x[n][m]
объявляет x
как 2-мерный массив указателей на целые числа, поэтому выделение памяти должно быть таким же простым, как x[i][j] = new int
, и, как и ожидалось, оно отлично работает. Теперь, если я изменил объявление на:
int (*x)[n][m]
x[i][j] = new int
больше не работает и приводит к ошибке компиляции.
x = (int(*)[n][m]) malloc (sizeof(int[n][m]))
однако компилируется. Из нескольких тестов, которые я выполнил, после выделения памяти различные комбинации объявления/распределения, похоже, не влияют на значения, хранящиеся в переменной. Я что-то упускаю? Итак, мой вопрос: Есть ли разница между int * x [n] [m] и int (* x) [m] [n]. Как int (* x) [n] [m] хранится в памяти?
Ответы
Ответ 1
int *a[n][m]
- это двумерный массив указателей на int
.
int (*p)[n][m]
является указателем на двумерный массив int
(это тип, который вы получаете, принимая адрес int[n][m]
).
В обоих случаях n
и m
должны быть компилированы константы времени, иначе объявления не являются законными в С++ (но находятся на C). Однако ваш компилятор может иметь расширение, чтобы его разрешить.
Сначала можно использовать для моделирования трехмерного массива. Я говорю симуляцию, потому что это не будет подходящий массив со смежным хранилищем, и типы будут отличаться в первую очередь. В каждом из элементов a
вы можете сохранить адрес в первый элемент массива целых чисел. Каждый из них может иметь разный размер и распределяться динамически. Вы также можете сохранить указатель на одно (возможно, выделенное стеком) целое число.
int i = 0;
int a1[2] = {};
int* a2[2][2];
a2[0][0] = a1; // array to pointer decay here
a2[0][1] = new int[42];
a2[1][0] = new int[84];
a2[1][1] = &i;
p
может указывать на один массив 2d или его массив:
int arr[2][3];
int (*p1)[2][3] = &arr; // arr decays to int(*)[3], so we need to take the address
int (*p2)[2][3] = new int[42][2][3]; // allocate 42 arrays dynamically
Ответ 2
Как вы можете легко обнаружить:
- int * x [n] [m] - двумерный массив указателей на int.
- int (* x) [n] [m] - указатель на двумерный массив из целых чисел.
Ответ на ваш вопрос заключается в том, что первым является массив, поэтому память является "встроенной" - она может быть статической, автоматической (в стеке) или в куче, в зависимости от того, где вы ее определяете.
Второй - это указатель на массив, и указатель должен быть инициализирован до того, как он будет использоваться. Скорее всего, память будет выделена в куче, но также возможно, что это может быть статический или автоматический массив, определенный в другом месте. Если вы получаете доступ к элементам массива перед инициализацией указателя, вы получаете Undefined Behavior.
Ответ 3
Хороший сайт для декодирования имен объявления C. Принимая ваши примеры (и подставляя n=1
и m=2
), мы видим:
int *x[1][2]
Переведено на:
объявить x как массив 1 из массива 2 указателя на int
В то время как
int (*x)[1][2]
Переведено на:
объявить x как указатель на массив 1 массива 2 из int