Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 自参考指针算法_C++_Pointers - Fatal编程技术网

C++ 自参考指针算法

C++ 自参考指针算法,c++,pointers,C++,Pointers,因此,给定以下代码: #include <iostream> #include <vector> int main(int argc, char* argv[]) { int i = 42; int* p = &i; std::cout << "*p: " << *p << std::endl; std::cout << "&p: " << &p <

因此,给定以下代码:

#include <iostream>
#include <vector>

int main(int argc, char* argv[]) {
    int i = 42;
    int* p = &i;

    std::cout << "*p: " << *p << std::endl;
    std::cout << "&p: " << &p << std::endl;
    std::cout << "p: " << p << std::endl;
    std::cout << "p + 1: " << (p + 1) << std::endl;
    std::cout << "p + 1: " << ((p + 1) == (int*)(&p)) << std::endl;
    std::cout << "*(p + 1): " << *(p + 1) << std::endl;
    return 0; 
}

(p+1)
是否存储了指向内存位置的指针
p
?通过这种方式可以得到
p
所指的值吗?

如果您记得指针和数组可以互换使用,您可能会发现,例如

p[1]

*(p + 1)
这意味着表达式
(p+1)
是指向
p
之后的
int
值的指针。由于
p
不指向数组,这意味着
(p+n)
对于正
n
是指向您尚未分配的对象的指针(超出范围),读取该值会导致未定义的行为。分配给它也是未定义的行为,甚至可以覆盖其他变量数据

要获取存储
p
的地址,请使用运算符的地址:
&p
。返回指向指针的指针(即类型为
int**
)。

在您的示例中
(p+1)
不指向您分配的任何存储,因此取消引用它会产生未定义的行为,应避免


编辑:另外,
(p+1)
本身的第二个输出是不可靠的,因为只有当指针是指向数组的指针时,才应该使用指针算术。因此,在我的机器上,表达式的计算结果为
false

p恰好在堆栈上的整数i的地址之后(以及之后的4个字节)分配了地址。some_ptr+1(实际上是some_ptr+1*sizeof(int))不是获取某个_ptr地址的一致方法,在这种情况下这只是巧合


因此,要回答您的问题,请使用\u ptr+1!=&虽然标准没有保证你在这里是幸运的,但是有些人认为你在这里是幸运的

然而,由于在对
(p+1)
进行解引用时,您在64位计算机上,因此只会得到p的较低32位

0x38D8A884 == 953723012

等式的右侧是您收到的输出。左边是程序输出所显示的p的32位低位。

p+1等于&p是一种随机情况。它只发生在像您这样的代码中,指针p跟随它所指向的对象。也就是说,p本身的地址sizeof(int)大于它所指向的对象的地址。例如,如果要在i和p之间再插入一个定义,则等式p+1==&p将无效。比如说

int i = 42;
int j = 62;
int* p = &i;
没有

指针算法虽然未经检查,但受到标准的限制。通常,它应该只在数组中使用,您可以使用它来指向数组元素或数组末尾的元素。此外,尽管允许将一个指针指向数组的末尾,但这样获得的指针是一个哨兵值,不应取消引用


那么,你观察到了什么?简单地说,
&p
p+1
,等等。。。是临时表达式,其结果必须在某处具体化。启用优化后,所述结果可能会在CPU寄存器中具体化,但如果不启用优化,则会在函数框架内的堆栈上具体化(通常)

当然,这个位置不是标准规定的,所以试图获得它会产生未定义的行为;即使它在你的编译器上使用了这组编译选项,对任何其他编译器,甚至是同一个编译器使用了任何其他选项也没有任何意义


这就是未定义行为的真正含义:它并不意味着程序崩溃,它只是意味着任何事情都可能发生,这包含了看似正常的情况。

p是指向int对象的指针。 &p是p的地址

示例中的堆栈如下所示:

Address        Type       Name        Value
0x7fff38d8a884 int        i           42
0x7fff38d8a888 int*       p           0x7fff38d8a884
按照堆栈的设置方式,p的地址正好在i的地址之后。在这个特殊的例子中,当您向p添加1时,它向下移动了4个字节,并在那里找到了值,这恰好是i的地址

队伍里发生了什么事

std::cout << "p + 1: " << ((p + 1) == (int*)(&p)) << std::endl;
std::cout << "*(p + 1): " << *(p + 1) << std::endl;

is
*(p+1)
-->编译器访问数组p的“第二个元素”,因为您可能使用的是x86_64系统,它是小尾端,存储在那里的十六进制值是0x38D8A884,是存储在p中的指针的下半部分(它转换为十进制的953723012),.

自我提醒-出去玩游戏时,不要写愚蠢的问题你在64位机器上吗?@DmitriChubarov是的。@remyabel我不相信你。Do
std::cout@remyabel我相信你。我忘了在64位机器上,指针必须与8字节边界对齐。
std::cout << "*(p + 1): " << *(p + 1) << std::endl;