Почему мы не можем использовать двойной указатель для представления двухмерных массивов?

Почему мы не можем использовать двойной указатель для представления двухмерных массивов?

arr[2][5] = {"hello","hai"};
**ptr = arr;

Вот почему в этом примере не работает двойной указатель (** ptr)?

Ответы

Ответ 1

Я попытаюсь сделать, как

int array[10][6];

а также

int **array2 = malloc(10 * sizeof *array2);
for (int i = 0; i < 10; ++i)
    array2[i] = malloc(6 * sizeof **array2);

выглядят как в памяти и как они разные (и что они не могут быть брошены друг к другу)

array выглядит так:

 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
| | | | | | | | | | | | | ..............| | | (10*6 elements of type int)
 - - - - - - - - - - - - - - - - - - - - - -
< first row >< second row> ...

array2 выглядит так:

 _ _ _ _ _ _ _ _ _ _ 
| | | | | | | | | | | (10 elements of type int *)
 - - - - - - - - - - 
 | |     ....      |     _ _ _ _ _ _
 | |                \-->| | | | | | | (6 elements of type int)
 | |                     - - - - - -
 | |
 | |      _ _ _ _ _ _
 |  \ -->| | | | | | | (6 elements of type int)
 |        - - - - - -
 |
 |
 |      _ _ _ _ _ _
  \ -->| | | | | | | (6 elements of type int)
        - - - - - -

Когда вы говорите array[x][y], он переводится в *((int *)array+x*6+y)

Хотя, когда вы говорите array2[x][y], он переводится в *(*(array2+x)+y) (Обратите внимание, что для array эта формула также работает (читается до конца сообщения, а затем Комментарии)).

То есть статический массив 2d на самом деле представляет собой 1-й массив с строками, помещенными в одну строку. Индекс рассчитывается по формуле row * number_of_columns_in_one_row + column.

Динамический массив 2d, однако, представляет собой всего лишь 1d массив указателей. Затем каждый указатель динамически выделяется для указания на другой 1-й массив. По правде говоря, этот указатель может быть любым. Может быть NULL или указывать на одну переменную или указывать на другой массив. И каждый из этих указателей устанавливается индивидуально, поэтому они могут иметь разные натуры.

Если вам нужно передать указатель на array где-нибудь, вы не можете отдать его в int ** (представьте, что произойдет. Значения int ячеек array интерпретируются как указатели и разыменованные → Bam! Segmentation fault!). Однако вы можете рассматривать array как 1d-массив int [6] s; это 1-й массив элементов с типом int [6]. Чтобы записать это, вы говорите

int (*p)[6] = array;

Ответ 2

Указание указателя на указатель означает, что каждая строка (или столбец, если вы предпочитаете думать об этом таким образом) может иметь другую длину от других строк/столбцов.

Вы также можете представить 2D-массив только указателем на элемент start и целое число, определяющее количество элементов в строке/столбце:

void matrix_set(double *first, size_t row_size, size_t x, size_t y, double value)
{
  first[y * row_size + x] = value;
}

Ответ 3

В C двумерный массив представляет собой массив массивов.

Вам нужен указатель-на-массив, чтобы ссылаться на него, а не на двойной указатель:

char array[2][6] = {"hello", "hai"};
char (*p)[6] = array;
//char **x = array;  // doesn't compile.

Для двойного указателя на ссылку на "2-мерные данные" он должен ссылаться на первый элемент массива указателей. Но двумерный массив в C (массив массивов) - это не то же самое, что массив массивов указателей, и если вы просто определяете двухмерный массив, то не существует соответствующего массива указателей.

Единственное сходство между ними - синтаксис [][], используемый для доступа к данным: сами данные структурированы совершенно по-другому.

Ответ 4

Создание массива указателей для каждой строки для получения объекта, который "выглядит", как многомерный массив переменного размера, является дорогостоящим выбором дизайна для синтаксического сахара. Не делайте этого.

Правильный способ создания многомерного массива с переменным размером - это что-то вроде:

if (w > SIZE_MAX/sizeof *m/h) goto error;
m = malloc(w * h * sizeof *m);
if (!m) goto error;
...
m[y*w+x] = foo;

Если вы хотите, чтобы он выглядел красиво, чтобы вы могли написать m[y][x], вы должны использовать другой язык, возможно, С++.

Ответ 5

Пусть начнется разговор о юридическом коде. То, что вы написали (предполагая char перед каждой декларацией), не будет компилироваться по нескольким причинам: у вас слишком много инициализаторов (шесть char для arr [0], а его размер равен 5) и конечно, char ** p не имеет типа, совместимого с char arr [2] [5]. Исправляя эти проблемы, получаем:

char arr[2][6] = { "hello", "hai" };
char (*p)[6] = arr;

Без двойного указателя. Если вы хотите получить доступ к одиночным символам выше, вам нужно указать элемент, из которого они пришли:

char* pc = *arr;

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

С++ не имеет двухмерных массивов. Первое определение выше определяет массив [2] или массив [6] из char. Массив implicite для преобразования указателя приводит к указателю на массив [6] из char. После этого, конечно, нет никакого массива для преобразования указателя, потому что у вас больше нет массива.