【问题标题】:Incompatible pointer type不兼容的指针类型
【发布时间】:2010-03-29 17:13:09
【问题描述】:

我有以下签名的功能:

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 中是否不是同一类型?

【问题讨论】:

  • 什么是MAX_BOXESMAX_DIMENSIONALITY?它们是宏、常量、...?

标签: c gcc


【解决方案1】:

我知道几天前有一个几乎完全一样的问题...不过现在找不到了。

答案是,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[][] 不是真正的类型;只能指定其中一种尺寸。但是这里问题的核心是二维数组和双指针是不是同一个东西。

【讨论】:

  • 酷 ASCII 艺术,但我认为箭头指向的框的第一个索引错误。
  • 我喜欢直观的解释。不过我想知道,如果它们使 * 和 [] 可以互换工作,为什么不为 *{n} 和 []{n} 工作?是不是太难了?
  • NomeN:这是因为它没有意义——您可以明智地将数组转换为指向其第一个元素的指针,因为数组只是一系列连续元素;但是您不能明智地将数组数组转换为指向指针的指针,因为指向指针的指针必须指向 at 指针,并且没有实际的指针指向它。咳咳。
  • @caf:感谢您的报道。我看到 NomeN 的评论并想,等等,视觉解释不是说明了为什么它们不能互换工作吗?不过话也不错!
  • @caf 如果您真的想在语言中拥有该功能,您不能进行深度转换吗?即将二维数组转换为指向子数组指针数组的指针。它需要一个额外的数组或至少可以迭代的东西,但它应该可以正常工作吗?还是我错过了一些基本的东西?
【解决方案2】:

您从未按照签名的要求构造指针数组。

有两种方法可以在 C 中处理 2D 数组。在一种情况下,您有很多东西,编译器会被告知尺寸是多少。它通过将行索引乘以列数来计算行的开头,然后添加列索引以查找该行中的元素。

另一种方法是使用指针向量,编译器只是取消引用向量以找到行的开头,但编译器不会自动为您生成这些,您必须自己做。

您的实际对象是第一种,但您的函数原型要求的是第二种。

所以你应该要么改变原型以匹配对象,要么构造一个行指针向量传递给函数。

【讨论】:

【解决方案3】:

C 中没有 int[][] 这样的类型,只有多维数组的第一部分可以不指定。所以int[][5] 没问题。

除了这里贴出的其他答案,如果你可以使用C99,你可以使用变量数组来完成你想要的:

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

这将适用于除 Microsoft 的 Visual C++ 之外的大多数平台。

【讨论】:

    【解决方案4】:

    当数组表达式出现在大多数上下文中时,它的类型会隐式地从“T 的 N 元素数组”转换为“指向 T 的指针”,并将其值设置为数组中第一个元素的地址。此规则的例外情况是数组表达式是 sizeof 或地址 (&) 运算符的操作数,或者如果数组表达式是用于在声明中初始化另一个数组的字符串文字。

    这在您的代码上下文中意味着在您对box_sort 的调用中,表达式boxes 的类型从M-element array of N-element array of int 隐式转换为pointer to N-element array of intint (*)[MAX_DIMENSIONALITY+1],因此您的函数应该期待像这样的参数类型:

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

    由于int *aint 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 视为 int 的一维数组并手动计算偏移量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-11-12
      • 2011-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多