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

Прочитав некоторые сообщения на этом сайте, я понял, что массив в C — это не просто постоянный указатель, как я изначально думал, а сам по себе отдельный тип, но в большинстве случаев массив распадается на постоянный указатель на первый элемент массива. . Из-за этой новой информации у меня возник вопрос. Предположим, у нас есть двумерный A[10][10]. Почему результатом выражения *A является указатель на первый элемент массива? Я думал, что в этом выражении A распадается на постоянный указатель на первый элемент массива A[0][0], и тогда применение косвенности должно дает нам значение A[0][0], но на самом деле он по-прежнему дает нам адрес первого элемента массива. Конечно, что-то не так с моей логикой или моим пониманием массивов или указателей, так где же я ошибаюсь?

Заранее спасибо.


person Юрій Ярош    schedule 28.11.2020    source источник


Ответы (3)


Первым элементом A является A[0], а не A[0][0].

Это потому, что A — это массив из десяти вещей. C не имеет двумерных массивов в качестве основного типа. Массив с несколькими измерениями получается или создается как несколько слоев массивов. Для компилятора результирующий тип по-прежнему является просто массивом, элементы которого являются дополнительными массивами.

Таким образом, в *A:

  • A преобразуется в указатель на его первый элемент. Этот указатель равен &A[0], поэтому *A становится *&A[0].
  • * и & отменяются, поэтому выражение становится A[0].
  • A[0] — это массив из десяти элементов, поэтому он преобразуется в указатель на его первый элемент, &A[0][0].
person Eric Postpischil    schedule 28.11.2020

*A или A[0] сам по себе является массивом из 10 элементов, и массив всегда выражается указателем на его первый элемент. Однако A[10][10] (скажем, массив целых чисел) фактически представляет собой блок памяти, содержащий 100 целых чисел, 10 из первой строки, за которыми следуют 10 из второй строки и так далее. Но если бы выражение *A или A[0] возвращало бы int вместо ptr для этой строки, было бы невозможно использовать выражение A[0][0], верно?

Однако, поскольку такой многомерный массив представляет собой единый блок памяти, его также можно привести к указателю, а затем получить к нему доступ с помощью выражения такого типа:

((int *)A)[iRow * 10 + iCol];

Что эквивалентно выражению:

A[iRow][iCol];

Но это, если это возможно для 2D-массива, объявленного таким образом:

int main()
{
    int A[10][10] = { 0 };
    A[9][9] = 9999;
    printf("==> %d\n", ((int *)A)[9 * 10 + 9]); //==> 9999
    return 0;
}

Это не так, если память потенциально состоит из отдельных блоков байтов (вероятно, требующих нескольких вызовов malloc), как с такими выражениями:

int * A[10]; // or
int ** A;
person dspr    schedule 28.11.2020
comment
Это приведение относится не к одномерному массиву, а к указателю. Это придирки, но когда это главный вопрос и ответ, лучше быть точным :). Вы могли бы привести к int(*)[100], чтобы сделать его указателем на одномерный массив. - person spectras; 28.11.2020
comment
Я исправил, спасибо! - person dspr; 28.11.2020

A распадается на постоянный указатель на первый элемент массива A[0][0]

Нет. Почему?

Стандарт C указывает, что *(pointer + integer) == pointer[integer], поэтому *A является эквивалентом *(A + 0), который равен A[0]. A[0] не даст вам элемент A[0][0], а только одномерный массив, который будет распадаться на указатель на первый элемент первой строки этого массива.

person 0___________    schedule 28.11.2020