指向引用的指针加上一个数组

时间:2013-10-17 08:44:14

标签: c arrays pointers reference

我刚读了一些关于指针的问题。这是代码:

int a[5]={1, 2, 3, 4, 5};
int *p = (int*)(&a + 1);//second line
cout<<(*p)<<endl;

我的编译器输出是0。什么是*p?它是指向数组a的指针吗?什么是&a+1的意思?

4 个答案:

答案 0 :(得分:8)

&a是数组的地址。

&a + 1也是一个地址,但这是什么1?它是指向sizeof a a 字节的指针。所以就像写int *p = &a[5];,然后你把它投到int *

现在为什么0?因为a[5]碰巧是0 - 请注意它不在界限范围内,可能是其他任何东西(未定义的行为)。

请注意,数组从零开始,这意味着索引来自0。实际上a[4]实际上是最后元素,a[5]超出范围。

答案 1 :(得分:8)

这是您的声明声明的含义:

                           p
                           |
                           v
a[0] a[1] a[2] a[3] a[4] | a[5]
---------(Length)------->

但是你想要得到这个(我假设):

     p
     |
     v
a[0] a[1] a[2] a[3] a[4] |
---------(Length)------->

您需要从声明语句中删除第二组括号以获取a[1]

int * p = (int *)(&a + 1);
// change to this:
int * p = (int *) &a + 1;

您获取错误值的原因与sizeof运算符,operator precedence和指针算法有关。在解释错误之前,让我解释一下。


运营商规模

sizeof运算符计算数据类型的大小(以字节为单位)。直接的例子:

sizeof (char)  // always returns 1
sizeof (int)   // usually returns 4 or 8
sizeof (int *) // usually returns 4 or 8

请注意这个有趣的例子:

int a[5];
sizeof (a) // returns sizeof (int) * 5

运营商优先顺序

运算符优先级是评估一系列运算符的顺序。括号中的任何内容都将首先进行评估。在计算括号之后,由运算符优先级决定表达式将被解决的顺序。

这是相关的运算符,它们在优先级表中排序:

Operator    Description    Associativity

()          Parenthesis    Left-to-right
(cast)      Cast           Right-to-left
&           Address of     Right-to-left
+, -        Plus, Minus    Right-to-left

指针算术

指针算法主要是用整数(或其他指针)添加,减去和乘以指针。你需要知道的(对于这个问题的范围)是:

int * p;

p = p + 1;

即使它 + 1,它实际上是在指针中添加sizeof (int)。 这是C标准的编写者的设计选择,因为它很多更常见 程序员想要将sizeof (int)添加到指针(将它们带到数组中的下一个整数)而不是添加1(它将指针放在数组中的第一个和第二个元素之间)。

更一般地说:

datatype p;
p = p + 1;
// actually means
p = p + sizeof (datatype);

这是一个相关的例子:

int a[5];
a = a + 1;
// actually means
a = a + sizeof (a);
// remember that sizeof (a) is going to be sizeof (int) * 5?

声明声明

返回声明声明:

int * p = (int *)(&a + 1);

您可能已经看到它出了什么问题:a + 1实际上意味着a + sizeof (a),这会让您超出数组的范围。这可能是0(通常是),也可能是其他随机值。

您可能没有注意到的是:

int * p = (int *) &a + 1;

实际上为您提供了数组中的第二个元素。这与运算符优先级有关。如果查看我放在链接中的运算符优先级表,强制转换的优先级高于&+运算符。因此,在评估表达式的其余部分之前,如果a被强制转换为(int *)而不是a[5],那么它就等同于:

int * a;
a = a + 1; /* and this would
    give you the second element
    in the array */

简单地说,如果要访问数组中的第二个元素,请更改:

int * p = (int *)(&a + 1);
// to this:
int * p = (int *) &a + 1;

答案 2 :(得分:5)

运算符&用于获取变量的地址。因此,&a是指向5个int的数组的类型指针:int (*)[5]

指针算术意味着当你有一个指针p时,p+1将指向下一个元素,即sizeof(*p)个字节。这意味着&a+1指向5*sizeof(int)块,即数组中最后一个元素之后的块。

&a+1强制转换为int *意味着现在您希望将此新指针解释为指向int的指针,而不是指向5个整数数组的指针。你说,从现在开始,这个指针会引用sizeof(int)个字节长的内容,所以如果你增加它,它将向前移动sizeof(int)个单位。

因此,*p正在访问a[5],这是一个超出界限的位置(超出最后一个位置),因此程序具有未定义的行为。它打印0,但它可能已经崩溃或打印其他东西。当未定义的行为发生时,任何事情都可能发生。

答案 3 :(得分:1)

int *p = (int*)(&a+1);

什么是*p? :

在您的代码中,*p是指向int类型的未知元素的指针。

让我们说出来:

&a是一个有效的指针表达式。可以将整数添加到指针表达式。

&a的结果:指向整个数组a[5]。其类型为int (*)[5]

sizeof *(&a)的结果是5,这是数组的大小。

&a +1的结果是指针表达式,其中包含当前指向的int之外的第一个&a的地址。

因此1对象超过&a*p指向的对象。因此,它是类型int未知元素。因此,访问unknown element是未定义的行为。这也解释了为什么输出为零。


旁注:

如果你真的想要访问数组中的第二个元素,你应该将1添加到指向数组第一个元素的指针。 a指向数组中的第一个元素,大小为sizeof(int*)

a+1的结果是数组中第二个元素的地址。

*(a+1)的结果是数组中第二个元素的值。 2