Cout和printf之间行为的C ++差异

时间:2019-02-11 20:17:18

标签: c++

我有以下代码段:

#include <iostream>
#include <stdio.h>
void foo(int**p)
{
    int y = 5; // memory for this is allocated, say at address 3000, and
               // that position of memory is filled with the value 5

    *p = &y;   //we equal the value (contents) at address 2000 to 3000;
}

int main(int argc, char **argv)
{
    int* p; 
    std::cout << &p << std::endl; 

    // p points to nowhere right now
    foo(&p); //we pass p's address to foo()

    printf("%d\n",*p); 
    std::cout << *p << std::endl;  
}

当我运行此代码时,printf输出5,但std :: cout打印无效数据。谁能解释为什么?

2 个答案:

答案 0 :(得分:2)

我认为值得深入了解关于C ++的基本误解:

// memory for this is allocated, say at address 3000, and
// that position of memory is filled with the value 5

在大多数编译器将解释代码的方式上,这是“ true”。但是,就C ++语言而言,这是实施细节

从语言的虚拟机角度,执行以下操作:

*p = &y;

您正在说:“ p指向的int指针对象现在指向对象y”。就这样。通过内存寻址完成此操作的事实再次是实现细节。

现在,当y超出范围时,p成为不指向有效对象的指针。取消引用此类指针是未定义的行为。 顺便说一句,即使后来有一个新的int对象被分配到相同的内存位置,也是如此。

关于未定义行为的有趣之处在于,它是编译器的空白。可以假定它永远不会发生,这往往会使您的程序执行似乎毫无意义的指令。

我想我要讲的是:除非您要处理指向charunsigned charstd::byte的指针,否则从内存地址的角度考虑指针实际上不是要走的路。

答案 1 :(得分:0)

是的,这绝对是指针问题,而不是cout / printf问题。

对于来自其他语言(例如Java)的人,这些人如果您不直接使用指针,可能会造成很多麻烦。您真的需要完全理解它们才能使用它们。在这种情况下,您不仅要处理指针,还要处理指向指针的指针。

在您的特定示例中,方法foo()使用一个指向指针的指针。很好,但是在执行此操作之前,您确实需要充分了解指针。

然后,它为变量y(在堆栈上)分配内存,并填充该内存。然后,将指针设置为指向y。

当您的方法返回时,堆栈将重置,并且堆栈中的所有操作都可能被丢弃。您不知道会发生什么。但是在这种情况下,您转过来调用另一个函数调用printf(),该函数在foo()所处的范围内在堆栈上分配空间,并将新数据放到那里。您的指针现在指向该新数据。

这就是您要打印的内容。

现在,如果您真正想要的是让foo()填写值,那么您真正需要的是:

  1. P应该是一个int,而不是int *,并且它将更改main内部的其他大多数代码。

  2. Foo应该采用int *,而不是int **。

  3. 您的最后一行应该是* p = y,而不是* p =&y。

换句话说,您将传递到foo中存储要返回的值的位置,而不是放置地址的位置。

当然,大多数人都会让foo返回您的int值:-)但是我认为您正在尝试更好地理解指针,这就是您这样做的原因。