C ++指针与数组表示法

时间:2014-12-05 13:27:13

标签: c++ arrays pointers

当我声明一个像这样的新数组时:

int foo[5]

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

*(foo+2)

访问数组的第三个元素?假设我正在制作2D阵列:

int foo[3][4]

foo现在是int**吗?

2 个答案:

答案 0 :(得分:5)

不,' foo'在两种情况下都是一个数组类型,但是当表达式中的指针需要&f 39时,它会隐式转换为一个(指向数组的第一个元素)。所有阵列都有此行为。在这种情况下,由于可以通过指针类型进行添加,但不能通过数组进行添加,' 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]'

您还可以创建参数为' array'的函数。引用(或指针)类型,以便只接受具有指定大小的那些(如果它们只是指针并且期望传递给衰变的数组,那么这是不可能的)。例如:

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

虽然由于遗留原因(或者因为别的东西?)而在语法上接受了数组参数,但是它们的真正含义永远不会被容忍,并且它们只是被调整过来'指针。

注意:数组类型隐式转换为它的第一个元素的指针有时被称为'数组指针衰减'。

答案 1 :(得分:-4)

没有数组不是指针,但在表达式中,它们被转换为指向其第一个元素的rvalue指针。 所以在这个表达式中

*(foo+2)

首先将foo转换为rvalue指针,然后使用指针算法。

对于此数组声明

int foo[3][4];

表达式中使用的名称foo将转换为int ( * )[4]

类型的右值指针

单词rvalue意味着您可能不会写++foo

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

考虑到如果您使用带有数组名称的运算符sizeof,则最后一个不会转换为指针。所以对于你的最后一个数组定义

sizeof( foo )

将等同于

3 * 4 * sizeof( int )

sizeof( int ( * )[4] )

将返回指针本身的大小。

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

int foo[3][4];

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