0

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

例 1。错误的程序:


“这个程序首先调用 SomeFunction 函数,它创建了一个名为 nNumber 的变量,然后让 pPointer 指向它。然后,问题出在哪里。当函数离开时,nNumber 被删除,因为它是一个局部变量。Local当执行离开定义它们的块时,变量总是被删除。这意味着当 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”。第一个程序不应该像教程所说的那样失败吗?

4

6 回答 6

3

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

关于未定义行为的好处(如果我可能会讽刺的话)是它是未定义的,您无法真正提前知道会发生什么。另请参阅nasal demons

于 2013-07-02T12:37:15.580 回答
0

两个程序都正确显示“*pPointer 的值:25”。第一个程序不应该像教程所说的那样失败吗?

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

于 2013-07-02T12:42:06.100 回答
0

那是未定义的行为。没有检查以确保被取消引用的指针是否指向有效值。在这里查看这个很棒的答案。

简而言之,

当变量超出范围时,在变量先前存储的位置处任何事情都是可能的(即使你这样做了deletedelete只是释放内存,它不一定会清除它)。

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

于 2013-07-02T12:42:09.033 回答
0

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

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

于 2013-07-02T12:42:42.163 回答
0

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

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

于 2013-07-02T13:13:29.343 回答
0

在第一个程序中,指针仍将指向内存中存储数字 25 的位置。这是对的。问题不在于数字 25 已被覆盖;那是它可能已被覆盖。其他程序有免费许可来处理该内存位置,而不会超出第一个程序的范围,但在实际改变该值之前,硬件仍然存储数字 25。

于 2013-07-02T13:22:56.220 回答