指针 - 动态分配混乱

时间:2013-07-02 12:34:54

标签: c++ pointers

我正在阅读这篇文章(http://www.codeproject.com/Articles/627/A-Beginner-s-Guide-to-Pointers),其中有一些代码可以解释我们应该使用它们的一个原因。例如。动态分配。

Eg.1。错误的程序:


“这个程序首先调用SomeFunction函数,它创建一个名为nNumber的变量,然后让pPointer指向它。然而,问题出在那里。当函数离开时,nNumber被删除,因为它是本地的当执行离开它们被定义的块时,局部变量总是被删除。这意味着当SomeFunction返回main()时,变量被删除。所以pPointer指向变量曾经的位置,不再属于这个节目。“

#include <stdio.h>

int *pPointer;

void SomeFunction()
{
    int nNumber;
    nNumber = 25;    

    // make pPointer point to nNumber:
    pPointer = &nNumber;
}

void main()
{
    SomeFunction(); // make pPointer point to something

    // why does this fail?
    printf("Value of *pPointer: %d\n", *pPointer);
}

Eg.2。正确的计划:


“当调用SomeFunction时,它会分配一些内存并使pPointer指向它。这次,当函数返回时,新内存保持不变,所以pPointer仍指向有用的东西。这就是动态分配!”

#include <stdio.h>

int *pPointer;

void SomeFunction()
{
    // make pPointer point to a new integer
    pPointer = new int;
    *pPointer = 25;
}

void main()
{
    SomeFunction(); // make pPointer point to something
    printf("Value of *pPointer: %d\n", *pPointer);
}

我的问题:


上面的解释对我来说完全有意义,我对使用指针的原因感觉很好。然后我决定运行程序看看会发生什么。我期待第一个显示* pPointer的随机数,因为25已被删除。两个程序都正确显示“* pPointer的值:25”。第一个程序不应该像教程所说的那样失败吗?

6 个答案:

答案 0 :(得分:3)

这是因为它是未定义的行为。您很幸运,printf函数没有写入该位置。

关于未定义行为的不错的事(如果我可能具有讽刺意味)是,它是未定义的,你不能真正告诉事先会发生什么。另请参阅nasal demons

答案 1 :(得分:0)

  

两个程序都正确显示“* pPointer的值:25”。不能   第一个程序失败了,因为教程说它会吗?

在第一个程序中,nNumber位于堆栈中。当SomeFunction()退出时,nNumber“超出范围”,也就是说从程序的角度来看它已不再存在。但是,用于该变量的内存仍然存在,并且它将包含与nNumber在范围内时所执行的值相同的值,直到在那里写入一些新值。当然,pPointer继续指向该位置,因此您可以继续查看该内存的值。当执行其他函数时,该内存最终将用于某个新变量,并且该值将发生变化。危险的是,如果你继续使用pPointer期望它保持有效,你会发现它指向的值会不断变化。

答案 2 :(得分:0)

这是未定义的行为。没有检查以确保被取消引用的指针指向有效值。在这里查看this精彩答案。

简而言之,

当变量超出范围时,在先前存储变量的位置可以进行任何操作(即使在执行delete后,delete只是释放内存,它不一定要擦除它)

它可能已经被覆盖,可能正在被覆盖,或者到目前为止没有任何改变。 (就像在你的例子中)。因为,它在一个有效的代码访问空间中,你找不到任何段错等。

答案 3 :(得分:0)

在堆栈上分配局部变量。当函数退出时,将修改指向堆栈顶部的指针,以便局部变量不在堆栈中,但不会擦除堆栈。因此,值25仍将位于pPointer指向的内存位置。如果使用局部变量调用另一个函数,则该内存将被覆盖。

printf()将覆盖该位置,但在执行printf()之前,将取消引用pPointer以在参数中使用。

答案 4 :(得分:0)

第一个程序工作的原因是因为在c ++中使用指向已销毁变量的指针是未定义的。但是c ++没有规定的是那个记忆会发生什么。使用c ++中所谓的堆栈帧来分配局部变量,或者如果您在函数完成后熟悉汇编语言“堆栈”,那么内存实际上并未被销毁,而是被保护不被覆盖。所以有一段时间指针可能会起作用,但在其他某个时间点,你指向的内存也可以被覆盖。

这种现象的技术解释是,当输入一个函数时,它的地址被压入堆栈段。然后将局部变量定义为此推送地址和堆栈指针之下的偏移量。这有效地为堆栈上的内存提供了对本地变量的访问。但是一旦函数离开而不是浪费时间覆盖那个内存,内存就不会受到以后操作的读写操作的保护,因为我们不知道内存将不再有效以及内存有多长有效不是一成不变的,经常波动。如果您正在寻找解释,此视频会提供一个很好的概述,而不会进入核心详细信息:http://www.youtube.com/watch?v=vcfQVwtoyHY

答案 5 :(得分:0)

在第一个程序中,指针仍然指向存储编号25的存储器中的位置。这是对的。问题不在于25号被覆盖了;这是可能被覆盖了。其他程序拥有免费许可,可以在没有超出第一个程序范围的情况下弄乱内存位置,但是直到实际出现改变该值的情况,硬件仍会存储数字25。