5
#include<stdio.h>
int main(int argc , char *argv[])
{
    int array[2][2] = {{1,100},{1000,10000}};

    int *pointer    = array;
    int *ppointer   = &array;
    int *pppointer  = array[0];
    int *ppppointer = &array[0];

    printf("%d\n",*pointer);
    printf("%d\n",*ppointer);
    printf("%d\n",*pppointer);
    printf("%d\n",*ppppointer);

    return 0;
}

四个指针指向数组的第一个元素。上面显示的哪个定义更好?而且我不知道为什么数组和 &array 的值相同?

4

7 回答 7

8

编译所有定义的唯一原因是您的 C 编译器在指针类型转换方面过于允许。如果你在这方面使用了一些使其更加迂腐的开关,它应该立即告诉你只有第三次初始化是有效的,而其余的都是错误的。

在大多数情况下(除了少数例外),当T[N]表达式中使用类型数组时,它会“衰减”(隐式转换)为指针类型T *- 指向其第一个元素的指针。换句话说,在任何数组的这种上下文中AA表达式都等价于&A[0]。唯一不会发生数组类型衰减的上下文是一元运算&符、sizeof运算符和用作char数组初始值设定项的字符串文字。

在您的示例array中是一个int [2][2]类型的值。当在初始化的右侧使用时,它会衰减为指针类型int (*)[2]。因此,这是无效的

int *pointer    = array;

右手边是int (*)[2],而左手边是int *。这些是不同的指针类型。你不能用另一个初始化一个。

int *ppppointer = &array[0];

与前一个完全相同:右侧产生一个int (*)[2]类型的值。由于同样的原因,它是无效的。

&array表达式产生一个int (*)[2][2]类型的指针。再次,出于这个原因

int *ppointer   = &array;

是无效的。

您的示例中唯一有效的初始化是

int *pppointer  = array[0];

array[0]int [2]类型的表达式,它衰减为int *类型 - 与左侧的类型相同。

换句话说,这里没有哪个“更好”的问题。你的初始化只有一个是有效的,其他的都是非法的。有效的初始化也可以写成

int *pppointer  = &array[0][0];

由于我上面描述的原因。现在,哪个右侧“更好”(array[0]&array[0][0])取决于您的个人喜好。


为了使您的其他初始化有效,指针应声明如下

int (*pointer)[2]     = array;
int (*ppointer)[2][2] = &array;
int (*ppppointer)[2]  = &array[0];

但是这样的指针将具有与指针不同的语义int *。你显然需要int *特别。

于 2012-07-21T20:17:53.530 回答
2

只有第三个实际上做了正确的事情。所有其他三个都是无效的 C++,并在我的 C 编译器中引起警告。通常最好编写同样是有效 C++ 的 C,因为在某些平台上,C++编译器也是 C 的推荐编译器(MSVC)。这也使得在 C++ 项目中包含 C 代码变得更容易,而无需大量的构建系统摆弄。

为什么您的编译器抱怨 1、2 和 4?右侧的表达式都没有要转换为的正确类型int*

  1. array具有int[2][2]可以转换为的类型int(*)[2],而不是int*
  2. &array是一个指针int[2][2]
  3. array[x]实际上有类型int*
  4. &array[x]有类型int**
于 2012-07-21T20:02:43.697 回答
1
int *pointer    = array;     //Incorrect
int *ppointer   = &array;    //Incorrect
int *pppointer  = array[0];  //Correct
int *ppppointer = &array[0]; //Incorrect

那是简短的版本。现在说说原因。

第一个指针不正确,因为您正在分配“数组”(这是一个没有任何进一步说明的指针)...但不是 int 之一,而是 int *[] 之一

第二个指针不正确,因为您要分配指针的地址……本质上是变量的地址,该地址保存指向数据的指针。

第三个是正确的,因为无论大小如何,您都会得到一个指向 int 数组的指针。

第四个不正确,因为您正在复制第一个数组的地址。这使它成为一个 int **,而不是一个 int *。

很抱歉进行了许多编辑……我一定很累。

于 2012-07-21T20:04:35.887 回答
0

简短的回答:

$猫decls.c

int main(void)
{
    int array[2][2] = {{1,100},{1000,10000}};
    int *pointer    = array;
    int *ppointer   = &array;
    int *pppointer  = array[0];
    int *ppppointer = &array[0];
}

$ clang decls.c -Wall -o decls

decls.c:4:7: warning: incompatible pointer types initializing 'int *' with an
      expression of type 'int [2][2]' [-Wincompatible-pointer-types]
        int *pointer    = array;
             ^            ~~~~~
decls.c:5:7: warning: incompatible pointer types initializing 'int *' with an
      expression of type 'int (*)[2][2]' [-Wincompatible-pointer-types]
        int *ppointer   = &array;
             ^            ~~~~~~
decls.c:7:7: warning: incompatible pointer types initializing 'int *' with an
      expression of type 'int (*)[2]' [-Wincompatible-pointer-types]
        int *ppppointer = &array[0];
             ^            ~~~~~~~~~

所以只有第三个声明是正确的。

稍微长一点的答案:当您在 C 中声明某些内容时,您使用一个表达式声明它,该表达式在评估时会为您提供左侧的类型。

因此,如果您有char name[][],则意味着当您拥有 时name[2][3],您将获得char。这反过来起作用: let A = name[3]; 你怎么能char摆脱A呢?通过这样做A[2]A一个char *

这就是为什么只有第三个声明是正确的:因为左边的声明表达式和右边的表达式都具有相同的类型。

于 2012-07-21T20:16:42.827 回答
0

它们都不是正确的(第三个不会出错,但我认为这不是海报想要的价值)。

它应该是:

int ** pointer1    = array;
int ** pointer2   = &array;        //This one is wrong
int ** pointer3  = array[0];      //This one is not correct in this case
int * ppointer3  = array[0];
int ** pointer4 = &array[0];
int * pointer5 = &array[0][0];

我更喜欢第一个和最后一个。

如果是一维数组,我更喜欢第一个,因为它表明数组基本上是指针。如果是多维数组,我会使用最后一个(因为它只需要解引用一次即可获取值,但要注意索引:例如如果要获取 1000,则需要使用pointer5[2]而不是pointer5[1][1]

于 2012-07-21T20:21:41.667 回答
-1

它们都是等价的。

&array 是数组的地址,它从与第一个元素相同的位置开始,因此 &array = &array[0]

array 是一个数组,但在某些情况下,它可以衰减为指向其第一个元素的指针,这就是为什么 array = &array = &array[0]

至于 int *pppointer = array[0];

我的第一印象是这应该是错误的。可能是别人可以解释。

更新:我的猜测是,这里的编译器将数组视为指针,给出:

int *pppointer = (&array)[0] = array[0]

于 2012-07-21T20:03:17.503 回答
-2

因此,您在数组中有一个数组。所以变量“array”实际上是一个指向另一个指针的指针。

所以如果你说:

int *pointer = array;

你有一个类型不匹配。*pointer是指向 int 的指针,但又array是指向另一个指针的指针。

当你说:

int *ppointer = &array;

你仍然有类型不匹配。&array 为我们提供了指向指针的指针的地址,我们只能将其分配给指向指针的指针。

当你说:

int *pppointer = array[0];

这是对的。方括号取消引用数组变量。所以array[0]实际上是指一个指向 int 的指针,它与*pppointer's 的类型相匹配。

当你说:

int *ppppointer = &array[0];

所以,我们有点回到我们从这里开始的地方。array[0]是指向 int 的指针,指向 int&array[0]的指针的地址也是如此,我们只能将其分配给指向指向 int 的指针的指针。

所以最后,第三个是唯一真正有效的。但是,我个人认为实现此目的的更好方法是:

int *pointer = *array;
于 2012-07-21T20:12:53.637 回答