В C почему (int *) и x [k] работают так же, как (int *) x [k] для двумерного массива x? - PullRequest
3 голосов
/ 14 февраля 2011

В следующем коде

 int x[2][3] = {{1,2,3},{4,5,6}};
 int* y1 = (int*)x[1];
 int* y2 = (int*)&x[1];

 int i;
 for(i=0; i < 3 ; i++)
 {
  printf("%i %i\n",y1[i],y2[i]);
}

, почему y1 и y2 указывают на одни и те же данные?

Я думаю, что x [1] - указатель на вторую строку данных, поэтому y1 должен быть правильным способом доступа к нему.Выражение & x [1] получает адрес указателя на вторую строку данных, так почему же y2 вообще работает?

Ответы [ 3 ]

4 голосов
/ 14 февраля 2011

С учетом объявления

int x[2][3] = {{1,2,3},{4,5,6}};

тип выражения x[1] равен "3-элементному массиву int".Если выражение массива не является операндом оператора адресации sizeof или & или не является строковым литералом, используемым для инициализации другого массива в объявлении, тип выражения преобразуется в «указатель на T» изначение выражения является адресом первого элемента массива.

Следовательно, в объявлении

int *y1 = (int *) x[1];

приведение не требуется;x[1] будет автоматически преобразован в тип int *, а y1 будет указывать на x[1][0].

В объявлении

int *y2 = (int *) &x[1];

выражение массива x[1] является операндом оператора address-of &, поэтому оно не преобразуется автоматически в тип int *.Тип выражения &x[1] - это «указатель на массив из 3 элементов int» или int (*)[3].В этом случае приведение необходимо, поскольку вы не можете неявно преобразовать указатель в массив T для указателя на T. Однако, вероятно, это не то, что вы хотите сделать;преобразование указателя в массив в указатель на скаляр, вероятно, приведет к путанице со стороны кого-либо.

Обратите внимание, что x[1] и &x[1] дают одинаковое значение (адрес первого элемента в массиве совпадает с адресом самого массива), но типы различны, что будет иметь значение для таких вещей, как операторы ++ и --.

Если вы хотите избежать приведений, перепишите эти объявления как

int *y1      =  x[1];
int (*y2)[3] = &x[1];
2 голосов
/ 14 февраля 2011

Ну, x[1] - это массив , а не указатель.Интересная деталь в том, что адрес массива - это сам массив :), так сказать, как:

int a[10] = {0};
assert(( int* )a == ( int* )&a);

Edit 0:

Чтобы ответить на ваш вопрос в комментарии:Строка типа int a[XXX]; резервирует часть памяти размером sizeof( int ) * XXX.Каждый раз, когда вы используете a для доступа к этой памяти, a заменяется адресом первого элемента.Компилятор знает этот адрес (или, по крайней мере, смещение первого элемента из сегмента данных или из стекового фрейма).Это устраняет необходимость временного хранения этого адреса, а затем разыменовывает этот временный адрес, чтобы получить доступ к самой памяти.Компилятор формирует выражение с (почти) прямым значением адреса.Таким образом, a здесь, в некотором смысле, не имеет места для адресации, поэтому для сохранения семантики &a замыкается на a.

С другой стороны, если вы передаете a в качестве аргумента функции это распад на указатель.

Все забавные вещи.Получите эту книгу, чтобы увидеть больше: "Эксперт C, Программирование Deep C Secrets"

1 голос
/ 14 февраля 2011

Поскольку двумерный массив не хранит фактический указатель каждой строки.В стеке хранится только адрес первого элемента.Поскольку массив x имеет фиксированный известный размер, смещения рассчитываются во время компиляции.

Выражение (int*)&x[1] понижает массив до указателя, возвращая то же значение.

Выражение x[1] возвращает адрес значения 4 в памяти.Используя оператор &, вы запрашиваете адрес адреса со значением 4, что в данном случае не имеет особого смысла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...