【问题标题】:unexpected output of C++C ++的意外输出
【发布时间】:2020-02-21 20:38:46
【问题描述】:

我发现以下程序的意外输出。

这里的指针ptr指向变量i的地址,i持有值10。这意味着ptr 也意味着10 的值。下一个ptr 递增一次。这意味着现在它持有价值11。但是在下面的程序中 ptr 会打印出12

#include <iostream>
using namespace std;    

int main()
{
    int i = 10;
    int *ptr = &i;
    int j = 2;
    j += *ptr++;

    cout<<"i : "<<i<<"\n";
    cout<<"j : "<<j<<"\n";
    cout<<"ptr : "<<*ptr<<"\n";
}

Output:

i : 10
j : 12
ptr : 12

所以我不明白为什么ptr 打印12 而不是11

【问题讨论】:

  • 未定义的行为可以做各种疯狂的事情。
  • 请选择一个标签。这是 C 还是 C++?
  • 未定义的行为。由于operator precedence*ptr++ 被解析为*(ptr++)。一定有一个副本,在某个地方,除非我的记忆在欺骗我..
  • 既然您期望11,您是否打算使用(*ptr)++
  • ptr 永远不会持有值 10 - *ptr 会。打印ptr&amp;i + 1&amp;j 并进行比较。

标签: c++ pointers undefined-behavior post-increment


【解决方案1】:

程序有未定义的行为。

此声明

j += *ptr++;

等价于

j += *( ptr++ );

所以指针现在指向变量 i 之后,即它没有指向有效对象。

所以这个说法

cout<<"ptr : "<<*ptr<<"\n";

调用未定义的行为。

编译器将变量 j 放在变量 i 之后。但是,C++ 标准未指定变量的顺序。

例如 gcc 编译器的输出与您显示的相同。

i : 10
j : 12
ptr : 12

虽然clang编译器的输出是

i : 10
j : 12
ptr : 4201824

你的意思是如下

j += ( *ptr )++;

在这种情况下,输出将是

i : 11
j : 12
ptr : 11

注意i的输出值是11,因为变量i是在已经对变量施加副作用的情况下输出的。

【讨论】:

  • 对因果读者的注意(Vlad 已经意识到这一点):“所以指针现在指向变量 i 之后,即它不指向有效对象。” 在变量之后有一个指向指针是可以的,但取消引用该指针是不行的(未定义的行为)。所以像 std::all_of(ptr, ptr+1, somepredicate) 这样的东西在指向非数组单个对象的指针上是可以的。
  • @Eljay:尽管标准允许创建刚刚过去的指针,以及任意指针之间的相等比较,但如果指向一个对象的指针和指针刚刚过去的另一个被比较,发现是相等的。
  • @supercat • 我的理解是ptrptr+1 可以,但是比较ptrsome_other_ptr+1 是不行的。这是一个非常有限(但有用)的情况,其中允许ptr+1,恰好与beginend 等单个对象的基于范围的算法一起工作。 (底线:C++ 抽象机与一个人的实际计算机不同;优化器可以以令人愉快的方式出人意料。假设人们发现“长时间的、深夜调试会话”令人愉快。)我相信所有这些都符合您的观点。
  • @Eljay:C 标准明确允许在任意指针之间进行 equality 比较,我很确定 C++ 标准也可以。 C 标准甚至明确承认在一个对象的刚刚过去的指针和指向另一个对象的指针之间进行比较的可能性,并指出如果第二个对象直接跟在第一个对象之后,这种比较将报告指针相等.
猜你喜欢
  • 2021-10-13
  • 1970-01-01
  • 2014-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-11
相关资源
最近更新 更多