Несовместимый тип указателя

У меня есть функция со следующей подписью:

void box_sort(int**, int, int)

и переменная следующего типа:

int boxes[MAX_BOXES][MAX_DIMENSIONALITY+1]

Когда я вызываю функцию

box_sort(boxes, a, b)

GCC дает мне два предупреждения:

103.c:79: warning: passing argument 1 of ‘box_sort’ from incompatible pointer type (string where i am calling the function)
103.c:42: note: expected ‘int **’ but argument is of type ‘int (*)[11] (string where the function is defined)

Вопрос состоит в том почему? Не являются ли интервал x [] [] и интервал ** x (и на самом деле интервал* x []) теми же типами в C?

9
задан James McNellis 19 June 2010 в 20:13
поделиться

4 ответа

Я знаю, что пару дней назад был почти такой же вопрос ... хотя сейчас не могу его найти.

Ответ таков: int [size] [] (см. Примечание внизу) и int ** определенно не одного типа. Вы можете использовать int [] и int * взаимозаменяемо во многих случаях, в частности в таких случаях, потому что массив распадается на указатель на первый элемент, когда вы передаете его в функцию . Но для двумерного массива это очень разные методы хранения.

Вот как они будут выглядеть в памяти для массива 2x2:

int a[2][2]:

__a[0][0]__|__a[0][1]__|__a[1][0]__|__a[1][1]__
  (int)       (int)       (int)       (int)

int **a (e.g. dynamically allocated with nested mallocs)

__a__
(int**)
  |
  v
__a[0]__|__a[1]__
  (int*)  (int*)
    |        |
    |        |
    v        ------------------>
__a[0][0]__|__a[0][1]__        __a[1][0]__|__a[1][1]__
  (int)       (int)              (int)       (int)

Второй массив можно построить следующим образом:

int **a = malloc(2 * sizeof(int*));
a[0] = malloc(2 * sizeof(int));
a[1] = malloc(2 * sizeof(int));

Примечание: как уже отмечали другие, int [] [] не настоящий тип; может быть не указан только один из размеров. Но суть вопроса здесь в том, являются ли двумерный массив и двойной указатель одним и тем же.

13
ответ дан 4 December 2019 в 13:46
поделиться

Когда выражение массива появляется в большинстве контекстов, его тип неявно преобразуется из «N-элементного массива T» в «указатель на T», а его value устанавливается равным адресу первого элемента в массиве. Исключениями из этого правила являются случаи, когда выражение массива является операндом операторов sizeof или адреса ( и ), или если выражение массива является строковым литералом, используемым для инициализации другой массив в объявлении.

В контексте кода это означает, что при вызове box_sort тип выражения box неявно преобразуется из массива M-элементов N-элементный массив от int до указатель на N-элементный массив int или int (*) [MAX_DIMENSIONALITY + 1] , поэтому ваша функция должна ожидать типы параметров например:

void box_sort(int (*arr)[MAX_DIMENSIONALITY+1], int x, int y)
{
   ...
}

Поскольку int * a и int a [] являются синонимами в объявлении параметра функции, отсюда следует, что int (* a) [N] является синонимом int a [] [N] , поэтому вы можете записать приведенное выше как

void box_sort(int arr[][MAX_DIMENSIONALITY+1], int x, int y)
{
}

, хотя я лично предпочитаю обозначение указателя, поскольку оно более точно отражает то, что происходит. Обратите внимание, что в вашей функции вы должны использовать индекс arr как обычно:

arr[x][y] = ...;

, поскольку выражение arr [x] эквивалентно * (arr + x) , указатель неявно разыменовывается.

Если вы хотите, чтобы box_sort работал с массивами произвольного размера (т. Е., массивы, в которых второе измерение не обязательно MAX_DIMENSIONALITY + 1), то один из подходов состоит в следующем:

int boxes[X][Y];
...
box_sort (&boxes[0], X, Y, x, y);
...
void box_sort(int *arr, size_t rows, size_t cols, int x, int y)
{
  ...
  arr[x*cols + y] = ...;
}

По сути, вы обрабатываете боксы как одномерный массив int и вычисляете смещения вручную.

0
ответ дан 4 December 2019 в 13:46
поделиться

Вы никогда не создавали массив указателей, как того требует подпись.

Есть два способа создавать 2D-массивы на C. В одном случае у вас просто много чего-то, и компилятору сообщают, каковы размеры. Он вычисляет начало строки, умножая индекс строки на количество столбцов, а затем добавляет индекс столбца, чтобы найти элемент в этой строке.

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

Ваш реальный объект относится к первому типу, но ваш прототип функции требует второго типа.

Таким образом, вы должны либо изменить прототип, чтобы он соответствовал объекту, либо построить вектор указателей строк для передачи функции.

1
ответ дан 4 December 2019 в 13:46
поделиться

В Си нет такого типа как int[][][], только первая часть многомерного массива может быть неопределенной. Так что int[][5] - это нормально.

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

void box_sort(int N, int M, int x[M][N]);

Это будет работать на большинстве платформ, кроме Visual C++ от Microsoft.

1
ответ дан 4 December 2019 в 13:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: