#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;数组的值相同?
答案 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*
。
array
的类型int[2][2]
可以转换为int(*)[2]
,而不是int*
&array
是指向int[2][2]
array[x]
实际上已输入int*
&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]
,A
为char *
。
这就是为什么只有第三个声明是正确的:因为左边的声明表达式和右边的表达式都有相同的类型。
答案 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;