Не может разыменовать многомерный массив, как ожидалось - PullRequest
0 голосов
/ 09 января 2019
int arr5[][3] = {{1,2,3}, {4,5,6}, {7,8,9}};

Переменная, объявляющая двумерный массив, содержит указатель на первый элемент в первом массиве. arr5 был определен как имеющий 3 столбца в каждой строке. Добавляя 1 к arr5, мы получаем адрес первого элемента во второй строке, добавляя 2 к arr5, мы получаем адрес первого элемента в третьей строке.

int *row1 = arr5;
int *row2 = arr5 + 1;
int *row3 = arr5 + 2;

Разыменование указателя на массив получает первый элемент в массиве.

printf("%d\n", *row1);  // prints 1
printf("%d\n", *row2);  // prints 4
printf("%d\n", *row3);  // prints 7

Мы можем разыменовать элементы в этих строках, используя [].

for (j = 0; j < 3; j++) {
  printf("%d%c", row1[j], (j==2)?'\n':' ');
} // prints 1 2 3

Мы можем напечатать второй ряд без использования скобок. Row2 теперь содержит адрес первого элемента во второй строке.

for (j = 0; j < 3; j++) {
  printf("%d%c", *(row2+j), (j==2)?'\n':' ');
}  // prints 4 5 6

Почему мы не можем заменить arr5 + 1 на row2 в приведенном выше примере? строка 2 содержит адрес arr5 + 1.

for (j = 0; j < 3; j++) {
  printf("%d%c", *((arr5+1)+j), (j==2)?'\n':' ');
}  // prints what looks to be addresses

Ответы [ 2 ]

0 голосов
/ 09 января 2019

За исключением случаев, когда это операнд оператора sizeof, _Alignof оператор, или унарный оператор '&', или используется строковый литерал чтобы инициализировать массив, выражение, которое имеет тип «массив типа» преобразуется в выражение с типом «указатель на тип» , которое указывает на начальный элемент объекта массива и не является именующий. C11 Standard - 6.3.2.1 Другие операнды - L-значения, массивы и функция десигнаторами (p3)

Поэтому, когда вы получаете доступ к arr5, вы эффективно используете указатель на массив int [3] . При попытке присвоить:

int *row1 = arr5;

Вы пытаетесь присвоить arr5 типа int(*)[3] row1, что составляет int*, что приводит к предупреждению:

"initialization from incompatible pointer type"

Чтобы устранить предупреждение, вам нужно разыменовать arr5, в результате чего получается тип int[3] (который при обращении преобразуется в указатель на первый элемент в строке), который совместим с int*. Например, немного переставив ваш пример, вы можете сделать:

#include <stdio.h>

int main (void) {

    int arr5[][3] = {{1,2,3}, {4,5,6}, {7,8,9}},
        *row1 = *arr5,
        *row2 = *(arr5 + 1),
        *row3 = *(arr5 + 2);
    size_t  nrow = sizeof arr5 / sizeof *arr5,
            ncol = sizeof *arr5 / sizeof **arr5;

    puts ("By row:");
    for (size_t j = 0; j < ncol; j++)       /* output row1 */
        printf ("%3d", *(row1 + j));
    putchar ('\n');

    for (size_t j = 0; j < ncol; j++)       /* output row2 */
        printf ("%3d", *(row2 + j));
    putchar ('\n');

    for (size_t j = 0; j < ncol; j++)       /* output row3 */
        printf ("%3d", *(row3 + j));
    putchar ('\n');

    puts ("\nBy array:");
    for (size_t i = 0; i < nrow; i++) {     /* output arr5 */
        for (size_t j = 0; j < ncol; j++)
            printf ("%3d", *(*(arr5 + i) + j));
        putchar ('\n');
    }
}

( примечание: row1[j] и arr5[i][j] обычно более читабельны, чем их эквиваленты для обозначения указателя)

Пример использования / Вывод

$ ./bin/ptr2arrayauto
By row:
  1  2  3
  4  5  6
  7  8  9

By array:
  1  2  3
  4  5  6
  7  8  9

Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

0 голосов
/ 09 января 2019

Обратите внимание на предупреждения компилятора. *((arr5+1)+j) не int, а int *.

предупреждение: формат «% d» ожидает аргумент типа «int», но аргумент 2 имеет тип «int *» [-Wformat =]

Примечание: (arr5+1)+j совпадает с (arr5+1+j). Я подозреваю, что ОП хотел *(arr5+1)+j здесь.

int main() {
    int arr5[][3] = {{1,2,3}, {4,5,6}, {7,8,9}};
    for (int j = 0; j < 3; j++) {
      printf("%d%c", *((arr5+1)+j), (j==2)?'\n':' '); // Warning here!!
    } 

    for (int j = 0; j < 3; j++) {
      printf("%d%c", *(*(arr5+1)+j), (j==2)?'\n':' ');
      //               ^ 
    }
return 0;
}

выход

-13412 -13400 -13388  UB UB UB
4 5 6                 OK OK OK
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...