为啥这个指针显示最后一个元素?

Posted

技术标签:

【中文标题】为啥这个指针显示最后一个元素?【英文标题】:Why does this pointer show the last element?为什么这个指针显示最后一个元素? 【发布时间】:2020-10-27 20:30:01 【问题描述】:

请向我解释b 指针如何显示最后一个元素。

无论数组有多长,它都会打印出最后一个元素。如果您在cout 中单独使用*b,则会显示数组外的数字。

#include <iostream>
#include <stdio.h>

using namespace std;

int main()

    int a[] = 1,2,3,4,5,6,7,8,9,10,11;
    int *b =(int*) (&a+1);
    cout << *(b-1) << endl;
    return 0;

【问题讨论】:

提示:sizeof(a) 是什么? 顺便说一句,这也是未定义的行为,但我还没有看到编译器不能按预期工作。 【参考方案1】:

这个表达式

&a+1

类型为int ( * )[11],指向数组a最后一个元素之后的内存。

在此声明中

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

您将表达式解释为具有指向数组 a 的最后一个元素之后的指针类型 int *。相反,你可以写

int *b = a + 11;

所以表达

b - 1

指向数组a的最后一个元素。

因此你可以这样想象*( b - 1 )这个表达式

*( a + 11 - 1 ) => *( a + 10 ) => a[10]

【讨论】:

【参考方案2】:

根据pointer arithmetic 规则,将指针递增/递减N 元素会将指针的值调整N * sizeof(T) 字节,其中T 是指针的取消引用类型。

&amp;a 是指向数组本身的指针,它的类型为int[11],因此您有一个指向数组开头的int(*)[11] 类型的指针。让我们在下图中将此称为A1

向该指针添加 +1 会将其前移sizeof(int[11])(又名sizeof(int)*11)字节,从而生成一个新的int(*)[11] 指向紧跟整个数组的内存地址的指针。我们在图中将其称为A2

然后类型转换这个新指针,所以现在你有一个指向数组末尾的int* 类型的指针。这是您分配给int *b 指针变量的内存地址。让我们在下图中将此称为B1

从该指针中减去 -1 会将其减少 sizeof(int) 字节,从而产生一个新的 int* 指针,指向数组中最后一个 int 元素的内存地址。让我们在下图中将此称为B2

因此,当您取消引用 b 以打印它所指向的 int 时,您正在打印数组中最后一个 int 的值。如果您不递减b,则它指向数组的末尾,并且您有未定义的行为。您可能只是打印出随机垃圾,或者您的应用程序可能会崩溃。任何事情都有可能发生。

---------------------------------------------------------------------
|  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9  |  10  |  11  |
---------------------------------------------------------------------
^                                                            ^      ^
|                                                            |      |
|_A1 --------------------------------------------------------|----->|_A2
                              +1                             |      |
                                                             |_B2 <-|_B1
                                                                -1

【讨论】:

其实就是UB。在数组类型之间转换指针到数组元素的类型是UB。但是,这种事情经常发生,std::complex 甚至开辟了一个例外,以便可以使用已知结构调用 C 函数。 @doug "在一个数组类型之间转换一个指针,到数组元素的类型是UB。" - UB怎么样?根据定义,就指针算术而言,指针可以指向对象的开头或结尾。所以我们获得了一个指向数组末尾的有效指针,将该指针转换为元素类型不会更改地址,只会更改指针类型。现在,强制转换的指针可以指向数组任何元素的开头或结尾,只要它仅在数组范围内被取消引用,我认为行为应该是明确定义的 T 的数组与 T 的类型不同。没有 UB,您不能将指针从一种类型转换为另一种类型(有一些像有符号无符号这样的剥离)。也就是说,这样做并不少见,据我所知,所有编译器都会产生预期的代码。就个人而言,我认为这不应该是 UB,但我不编写标准。

以上是关于为啥这个指针显示最后一个元素?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的程序显示此编译错误?

ios开发中tableview的最后一个cell为啥显示不完整

请问为啥同一个压缩文件显示的大小却不同呢?

为啥当分配看起来合适时指针分配显示左值错误?

当我想修改指向常量整数的指针时,为啥我的编译器不显示错误?

为啥这两种方法不一样? [关闭]