Несовместимый тип указателя - PullRequest
9 голосов
/ 29 марта 2010

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

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)

Вопрос почему ? Разве int x [] [] и int ** x (и фактически int * x []) не являются одинаковыми типами в C?

Ответы [ 4 ]

13 голосов
/ 29 марта 2010

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

Ответ таков: 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[][] не является реальным типом; только один из размеров может быть не указан. Но суть вопроса здесь заключается в том, являются ли двумерный массив и двойной указатель одинаковыми.

1 голос
/ 29 марта 2010

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

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

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

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

1 голос
/ 29 марта 2010

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

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

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

Ваш фактический объект относится к первому типу, но ваш прототип функции запрашивает второй тип.

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

0 голосов
/ 29 марта 2010

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

В контексте вашего кода это означает, что при вызове box_sort тип выражения boxes неявно преобразуется из M-element array of N-element array of int в pointer to N-element array of 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] = ...;
}

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

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