哪个定义更好?

时间:2012-07-21 19:55:38

标签: c

#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;
}

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

7 个答案:

答案 0 :(得分:8)

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

在大多数情况下(少数例外),当表达式中使用类型T[N]的数组时,它会“衰减”(被隐式转换)到指针类型T * - 一个指向的指针它的第一个元素。换句话说,在任何数组A的上下文中,A表达式等同于&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 *专门。

答案 1 :(得分: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. 的指针
  4. array[x]实际上已输入int*
  5. &array[x]的类型为int**

答案 2 :(得分:1)

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

那是短版本。 现在是有原因的。

第一个指针不正确,因为你正在指定'array'(这是一个没有任何进一步规范的指针)......但不是int之一,而是int * []

之一

第二个指针不正确,因为你要指定指针的地址......本质上是变量的地址,它保存指向数据的指针。

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

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

很抱歉很多编辑......我一定很累。

答案 3 :(得分:0)

简短回答:

  

$ cat 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。这反过来说:让A = name[3];如何从char中获得A?通过执行A[2]Achar *

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

答案 4 :(得分: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,你需要使用{{ 1}}而不是pointer5[2]

答案 5 :(得分:-1)

它们都是等价的。

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

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

至于     int *pppointer = array[0];

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

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

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

答案 6 :(得分:-2)

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

所以,如果你说:

int *pointer = array;

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

当你说:

int *ppointer = &array;

您仍然存在类型不匹配的问题。 &amp; array给出了指向指针的地址,我们只能指向指向指针的指针。

当你说:

int *pppointer = array[0];

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

当你说:

int *ppppointer = &array[0];

所以,我们回到了我们从这里开始的地方。 array[0]是指向int的指针,因此&array[0]是指向int的指针的地址,我们只能将指针指向指向int的指针。

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

int *pointer = *array;