2014-12-05 45 views
7

当我宣布这样一个新的数组:C++指针VS排列标记

int foo[5] 

foo真是一个指向数组的第一个元素?我能做到这一点:

*(foo+2) 

访问数组的第三个元素?比方说,我正在做一个二维数组:

int foo[3][4] 

foo现在int**

+11

* foo是否指向数组的第一个元素?* - 不,它是一个数组。 * foo现在是一个int \ * \ *?* - 不,它是一个2D数组。请参阅[数组](http://stackoverflow.com/questions/4810664/how-do-i-use-arrays-in-c) – chris 2014-12-05 13:27:48

+0

@chris,所以如果我想用指针表示法迭代它,我会需要做一个'int * ptr =&foo [0]'? – n0pe 2014-12-05 13:29:12

+0

@maxmackie'int * ptr = foo'就够了。 – 2014-12-05 13:29:33

回答

5

否,“富”是在这两种情况下的阵列型,但是当一个指针与“富”表达预期,它的隐式转换为一个(其指向数组第一个元素)。所有数组都有这种行为。在这种情况下,由于可以通过指针类型完成附加操作,但不能通过数组完成,所以'foo'被转换为'int *'。

*(foo+2) // 'foo' is implicitly converted into 'int *', pointing to 'foo' first element 

foo + 1 //same as above 

但现在你可能会问,什么是“数组”类型,以及为什么我们应该永远使用它的属性,而不是隐含指向第一个元素演员。事情是,他们并不多。你可以告诉物体的大小与类型数组是这样的:

sizeof(foo) //returns the size which array 'foo' occupies 

,并得到它的地址通过使用“&”运营商:

&foo // '&foo' has type of 'int (*)[5]' 

您还可以使用“数组的参数来创建功能'引用(或指针)类型,以便只接受具有指定大小的引用(这是不可能的,如果它们只是指针,并期望数组传递到这样的衰减)。示例:

void func(int (&)[5]); 

void func1(int (*arg)[5]); // should be accessed by '*arg', allow the use of null-pointers 

void func2(int *); //same as the misleading 'void func2(int [5])' or 'void func2(int [6])' etc. 

int foo[5]; 

int foo1[6]; 

func(foo); // 'foo' type is ('int [5]') - ok 

func1(&foo); // '&foo' type is ('int (*)[5]') - ok 

func(foo1); // 'foo1' type is ('int [6]') - not allowed, param type is 'int (&)[5]' ! 

func1(&foo1); // '&foo1' type is ('int (*)[6]') - not allowed, param type is 'int (*)[5]' ! 

func2(foo); // 'foo' is implicitly converted to 'int *' - ok 

func2(foo1); // 'foo1' is implicitly converted to 'int *' - ok 

在数组为2D的第二种情况下 - 应用相同的属性。它的声明意味着这个:'一个由3个元素组成的数组,其中4个元素的数组类型为int'所以它实际上只是一个数组数组而已。它是第一个元素转换的隐式指针,不是'int **'类型,而是'int(*)[4]',因为它的每个元素都是另一个数组。

的声明可以这样写太:

int (foo[3])[4]; 

还要注意“阵列”不能分配,所以他们不能按值传递或函数返回。我的意思是:

int funcReturningArray()[2]; //not allowed 

int funcAcceptingArray(int [2]); //just converted into pointer 

int funcAcceptingArray(int *); //same as above 

虽然阵列参数语法的,因为传统的原因,接受(?还是因为别的什么),其真正的意义是永远不会容忍,他们只是“调整”为指针。

注意:将数组类型隐式转换为其第一个元素的指针有时被称为“数组指向衰减”。

+0

大体正确的答案,但可以改进:1。你可能应该说数组*会衰减*为一个指针而不是“它被隐式地转换为一个”。铸造这个词通常意味着程序员强迫编译器去做一些反对它更好的知识的事情,而不是隐晦地毫不费力地改变底下的类型。通过大幅度缩短评论,您还可以显着提高大码块的可读性。类似于:'//错误:错误类型'或'// ok:foo衰变为int *'。 – cmaster 2014-12-05 17:59:48

+0

'decay'是关键字。应该把它放在开头 – texasbruce 2014-12-05 18:21:57

-4

没有数组不是指针,但在表达式中,它们被转换为右值指针指向它们的第一个元素。 因此,在这个表达式

*(foo+2) 

在第一FOO被转换为右值指针,然后使用指针运算。

对于这个数组声明在表达式中使用的

int foo[3][4]; 

名称FOO被转换为右值类型的指针int (*)[4]

字右值意味着,例如,你可以不写++foo

即表达式中使用的数组名称的编译器将创建一个临时对象,该临时对象是数组第一个元素的临时对象。

请注意,如果您正在使用例如运算符sizeof的数组名称,则最后一个将不会转换为指针。因此,对于你最后一个数组定义

sizeof(foo) 

将相当于

3 * 4 * sizeof(int) 

sizeof(int (*)[4]) 

将返回指针本身的大小。

最后,如果您将运算符&应用到数组名称,那么您将获得一个指向数组本身的指针。例如

int foo[3][4]; 

int (*ptr_to_foo)[3][4] = &foo; 
+0

我真的不明白谁downvoted这个回答,这是完全正确的! – cmaster 2014-12-05 18:02:30

+0

_“这是表达式中使用的数组名称的编译器创建一个临时对象,它是数组的第一个元素的临时对象。”_解析错误... – 2014-12-05 19:07:04