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

use*_*534 2 c arrays pointers reference

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

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

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

Mar*_*oun 8

&a 是数组的地址.

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

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

请注意,数组是从零开始的,这意味着索引来自0.所以实际上a[4]最后一个元素,a[5]是出界的.

  • 请注意,在'&a + 1`周围使用括号是产生差异的原因.如果要取消括号,指针将变为远离数组地址的`sizeof(int*)`字节,(因为强制转换).这将使它成为第二个元素的地址. (4认同)
  • 访问越界是非法的,接下来是未定义的行为. (3认同)
  • +1为什么`a [5] = 0`因为`a [4] = 5`和`a [5]`超出界限...在数组长度之外它恰好是0 ,它可能是随机数据. (2认同)

tay*_*10r 8

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

                           p
                           |
                           v
a[0] a[1] a[2] a[3] a[4] | a[5]
---------(Length)------->
Run Code Online (Sandbox Code Playgroud)

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

     p
     |
     v
a[0] a[1] a[2] a[3] a[4] |
---------(Length)------->
Run Code Online (Sandbox Code Playgroud)

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

int * p = (int *)(&a + 1);
// change to this:
int * p = (int *) &a + 1;
Run Code Online (Sandbox Code Playgroud)

获得错误值的原因与sizeof运算符,运算符优先级和指针算法有关.在解释错误之前,让我解释一下.


运营商规模

sizeof运算符计算一个数据类型的大小(以字节计).立即示例:

sizeof (char)  // always returns 1
sizeof (int)   // usually returns 4 or 8
sizeof (int *) // usually returns 4 or 8
Run Code Online (Sandbox Code Playgroud)

请注意这个有趣的例子:

int a[5];
sizeof (a) // returns sizeof (int) * 5
Run Code Online (Sandbox Code Playgroud)

运营商优先权

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

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

Operator    Description    Associativity

()          Parenthesis    Left-to-right
(cast)      Cast           Right-to-left
&           Address of     Right-to-left
+, -        Plus, Minus    Right-to-left
Run Code Online (Sandbox Code Playgroud)

指针算术

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

int * p;

p = p + 1;
Run Code Online (Sandbox Code Playgroud)

即使它 + 1,它实际上是添加sizeof (int)到指针.这是一个设计选择C标准的作家,因为它是很多更常见的程序员要添加sizeof (int)指针(这使他们的下一个整数数组)比增加1(这使在第一之间的指针和数组中的第二个元素).

更一般地说:

datatype p;
p = p + 1;
// actually means
p = p + sizeof (datatype);
Run Code Online (Sandbox Code Playgroud)

这是一个相关的例子:

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

宣言声明

回到你的声明声明:

int * p = (int *)(&a + 1);
Run Code Online (Sandbox Code Playgroud)

你可能已经看到它有什么问题了:a + 1真的意味着a + sizeof (a),这会让你超出数组的范围.这可能是0(通常是)或者可能是其他随机值.

您可能没有注意到的是:

int * p = (int *) &a + 1;
Run Code Online (Sandbox Code Playgroud)

实际上给你数组中的第二个元素.这与运算符优先级有关.如果你看一下,我把在一个链接的运算符优先级表,铸就具有更高的优先级比&+运营商.因此,如果在表达式的其余部分被计算之前a被转换为a (int *)而不是a[5]之前,则它变为等效于:

int * a;
a = a + 1; /* and this would
    give you the second element
    in the array */
Run Code Online (Sandbox Code Playgroud)

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

int * p = (int *)(&a + 1);
// to this:
int * p = (int *) &a + 1;
Run Code Online (Sandbox Code Playgroud)


Fil*_*ves 5

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

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

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

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