一小段运行奇怪的程序

C++语言 码拜 6年前 (2015-05-11) 411次浏览 0个评论
#include <stdio.h>

int *p = NULL;

void fun()
{
    int i = 10;
    p = &i;
}

void main()
{
    fun();

    printf("第1次:*p = %d\n", *p);
    printf("第2次:*p = %d\n", *p);
    printf("第3次:*p = %d\n", *p);

}

以上代码片段先猜猜执行结果是多少。
全是无效值?还是全是10?执行一下便知道,但为何如此?

另外,执行完 fun之后,Sleep 1秒,执行结果也不同。
另外,Debug下和Release下结果也不同
另外,Linux下gcc编译结果同VS下Debug结果
……

大家分析一下,什么原因?

调用函数之后p就成了野指针了。所以指向的地方变换了,值也就变化了?
引用 1 楼 FightForProgrammer 的回复:

调用函数之后p就成了野指针了。所以指向的地方变换了,值也就变化了?

指向地方可能没变,只是指向的地方(也就是地址)保存的数据变化了

知道什么叫做“结果是未定义”吗?

未定义的代码还去预测?浪费生命!

高手呀,当然不同了
fun()调用完之后,指针指向的值就没有了吧。*p应该都是NULL吧
没有实际意义!
引用 3 楼 lovesmiles 的回复:

知道什么叫做“结果是未定义”吗?

未定义的代码还去预测?浪费生命!

顶无聊的问题。

int i = 10;  这里定义的变量 i 在出了 void fun() 的作用域之后,由于 i 是在栈上分配的,系统自动回收i 对应的内存。

所以, i 对应的内存已经被释放了, 由于这块内存被释放,所以系统会分配给其他人用。

因此, i 对应的内存已经是别人的东西了,你再去访问,你永远不会知道他的值是谁写进来的。

求楼上那些说是无聊问题的大神讲解上述现象的原因
要是讲不出来就别装逼了,人家问个问题看把你急的,又没浪费你生命,觉得浪费生命就别回啊,最看不惯这种人
这里提出这个问题是想让大家分析出现这样结果的原因,借此探究程序堆、栈内存的分配、使用以及回收规则,从而帮助提升代码执行效率。不喜欢这种问题的朋友看看就好。
大家在新手期都是这么好奇过来的,然后回头去看,这样的好奇是完全地浪费生命而已。
你的那些探究是不会有实际价值的结论了,和你的帮助XXX就更靠不上了。
多尊重别人的经验吧。

引用 10 楼 cjqpker 的回复:

这里提出这个问题是想让大家分析出现这样结果的原因,借此探究程序堆、栈内存的分配、使用以及回收规则,从而帮助提升代码执行效率。不喜欢这种问题的朋友看看就好。

野指针,指哪算哪?哪有什么值。就好比你随手在地图上点了一个地方你知道是那里吗?
不能指望错误代码得到确定的正确结果。
10分
没执行,不过应该全是10吧,执行fun的时候变量i的内存位置应该跟*p这个形参压进去的位置相同。
执行sleep会变化是因为sleep也是一个函数调用,会压栈,把原来内存位置的东西改写。
debug和release不同是因为,debug版本会加入一些调试信息。
至于gcc,配置一下应该也可以去掉debug信息生成一个release版的
10分
如果是单线程程序,第一个应该是10,但第二开始应该就不会是10了,而是int类型的随机值了!!
因为保存在栈空间的临时变量i的内存空间已经被重新写如新的数值了!
 这个p地址 其实保存了一个栈空间的一个内存地址 这个地址的内容是随时被写人被赋值的
printf后 这个内存地址的内容就被重新写了
print参数是传值不是传指针,你把值当指针,得到的数是随机数,弄不好可能程序还会崩溃(访问越界)
fun 执行完了之后 i 就会被回收掉 p就成野指针了  执行第一次打印的时候会是10  之后就不是了
引用 16 楼 worldy 的回复:

print参数是传值不是传指针,你把值当指针,得到的数是随机数,弄不好可能程序还会崩溃(访问越界)

没有传指针啊,传的是指针p取值后整形值啊

引用 14 楼 windfantsy 的回复:

没执行,不过应该全是10吧,执行fun的时候变量i的内存位置应该跟*p这个形参压进去的位置相同。
执行sleep会变化是因为sleep也是一个函数调用,会压栈,把原来内存位置的东西改写。
debug和release不同是因为,debug版本会加入一些调试信息。
至于gcc,配置一下应该也可以去掉debug信息生成一个release版的

分析的有道理,但结果如15楼所描述

引用 15 楼 tangtangtangbaoli 的回复:

如果是单线程程序,第一个应该是10,但第二开始应该就不会是10了,而是int类型的随机值了!!
因为保存在栈空间的临时变量i的内存空间已经被重新写如新的数值了!
 这个p地址 其实保存了一个栈空间的一个内存地址 这个地址的内容是随时被写人被赋值的
printf后 这个内存地址的内容就被重新写了

结果的确如此!

函数里的局部变量一离开作用域马上被释放,指针所指向的内容成了未定义的了,至于是什么值,得看当时系统在该内存处放了什么东西咯。
int i是函数内部的。临时变量,函数执行完了,这个就没有意义了。
如果你定义在外面就不会变。
10分
另外,执行完 fun之后,Sleep 1秒,执行结果也不同。
另外,Debug下和Release下结果也不同
另外,Linux下gcc编译结果同VS下Debug结果
===========
首先,我们都知道,这个已经是野指针了。指针所指向的内存不归你的程序管了。系统可以根据具体情况分配其他人。

所以:
第一种情况:一秒之内,系统把内存分配其他进程然后又释放掉再分配给另外的进程是可以做到的,而且说不定已经被重新分配很多次了。
第二种情况:Debug下,是可以分辨野指针的。我不清楚编译器是怎么做到的。但是单凭这点,我们就应该知道,debug下分配的内存的方式给release下的应该是不一样的,所以,释放后,结果肯定也是不一样的。
第三种情况:不好理解了。如果是地址一样,值不一样,说明是因为编译器的工作方式一样导致的吧。如果地址和值都一样,可能是计算机本身环境的结果。

以上只是我个人根据所学推理的。要解释你的情况,应该是要学编译原理的。

10分
引用 18 楼 cjqpker 的回复:
Quote: 引用 16 楼 worldy 的回复:

print参数是传值不是传指针,你把值当指针,得到的数是随机数,弄不好可能程序还会崩溃(访问越界)

没有传指针啊,传的是指针p取值后整形值啊

printf(“第1次:*p = %d\n”, *p);
是看错了

你这个问题是指针指向了栈区的变量!这是错误的,函数返回后,调用了别的函数,别的函数的参数及返回值就会覆盖原来的值,计算式的临时变量也会覆盖原来的值,因此,无法预测你的p指向位置的内容是什么

理解讨论之前请先学会如何观察

计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构……

对学习编程者的忠告:
多用小脑和手,少用大脑、眼睛和嘴,会更快地学会编程!
眼过千遍不如手过一遍!
书看千行不如手敲一行!
手敲千行不如单步一行!
单步源代码千行不如单步Debug版对应汇编一行!
单步Debug版对应汇编千行不如单步Release版对应汇编一行!

VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)

    printf(“第1次:p = %x\n”, p);
你顺带也把p的地址也打印出来看下,你这代码,p指向的地址内容是不确定的,因为i是局部变量,函数退出后指定的内存被回收,p指向的内容不确定。
#include <stdio.h>
 
int *p = NULL;
 
void fun()
{
    int i = 10;
    p = &i;  //指向栈内存
}
 
void main()
{
    fun();
 
    printf(“第1次:*p = %d\n”, *p); 输出栈内存中的数值,但是指针所指向的栈内存,在fun使用后,已经释放
    printf(“第2次:*p = %d\n”, *p);在你这段调用过程中,这段内存,可能被修改,所以数据变动
    printf(“第3次:*p = %d\n”, *p);
 
}
引用 9 楼 lwjpker 的回复:

求楼上那些说是无聊问题的大神讲解上述现象的原因
要是讲不出来就别装逼了,人家问个问题看把你急的,又没浪费你生命,觉得浪费生命就别回啊,最看不惯这种人

无知

全部都是无效值 
ps 哪怕输出10 这个10 也是无效值
其实电脑开机后物理内存的每个字节都是可读写的,从来不会因为所谓的new、delete或malloc、free而被创建、销毁。区别仅在于操作系统内存管理模块在你读写时是否能发现并是否采取相应动作而已。操作系统管理内存的粒度不是字节而是页,一页通常为4KB。
原因找到了吗?要穷追不舍啊。

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明一小段运行奇怪的程序
喜欢 (0)
[1034331897@qq.com]
分享 (0)

文章评论已关闭!