2013-07-02 59 views
0

我正在阅读这篇文章(http://www.codeproject.com/Articles/627/A-Beginner-s-Guide-to-Pointers),它有一些代码来解释为什么我们应该使用它们。例如。动态分配。例如:指针 - 动态分配混淆

例如:不正确的程序:。


“该程序首先调用SomeFunction函数,它创建了一个名为n已接收变量,然后使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); 
} 

例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”。第一个程序不应该像教程所说的那样失败吗?

+0

[返回本地地址或临时变量](http://stackoverflow.com/questions/2744264/returning-the-address-of-local-or-temporary-variable) – Lstor

+0

这是一个很好的解释:http://stackoverflow.com/questions/ 6441218/can-a-local-variables-memory-be-accessible-scope-scope/6445794#6445794 – Lstor

回答

3

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

不错事情(如果我可能是讽刺)关于未定义的行为,是因为它是未定义的,你不能真正知道事先会发生什么。另见nasal demons

+0

从技术上讲,pPointer将在printf()被执行之前解除引用,所以至少它是健壮的! – user1158559

+0

@ user1158559啊是的,这是正确的,这就是为什么它“工作”。 –

0

这两个程序都正确显示“Value of * pPointer:25”。第一个程序不应该是 ,因为本教程会说它会失败?

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

0

那就是未定义的行为。没有检查来确保被取消引用的指针指向一个有效值。检查this真棒的答案在这里。

总之,

当变量超出范围,任何事情都是可能的,其中变量以前存储的位置(即使你做deletedelete只是释放它不必然消灭它的内存) 。

它可能已被覆盖,可能正在被覆盖的过程中,或者至今没有任何改变。 (就像你的例子)。因为它在一个可以被你的代码访问的空间中,所以你没有发现任何段错误等。

+0

感谢球员我现在明白为什么我们需要在这种情况下使用指针。 – user2364266

0

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

0

第一个程序工作的原因是因为在C++中使用指向已销毁变量的指针是未定义的。但是C++没有规定的是该内存会发生什么。局部变量是使用C++中所谓的Stack Frame进行分配的,或者如果在函数完成后熟悉汇编语言“The Stack”,那么经常存储器并未被实际销毁,而只是不能被覆盖保护。所以一段时间指针可能工作,但在其他时间点,您指向的内存也可以被覆盖。

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

0

在第一个程序中,指针仍然指向内存中存储数字25的位置。这是对的。问题不在于数字25被覆盖;它的可能已被覆盖。其他程序拥有免费的许可证,可以在不超出第一个程序的限制的情况下解决该内存位置问题,但是直到某些事情实际发生变化,硬件仍然存储了数字25.