首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 培训 数据库 书店 程序员
中国软件网
欢迎您:游客 | 登录 注册 帮助
  • 求教一个关于 临时变量生存周期的问题
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zcncts
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    • 结帖率:
    发表于:2008-10-29 23:50:12 楼主
    #include <iostream.h>

    int* gettest()
    {
    int a=1;
    int *b=&a;
    return b;
    }
    void main()
    {
    int *x=gettest();

    cout < <*x < <endl;//输出结果 是 1  正确
    cout < <endl;
    cout < <endl;
    cout < <endl;
    cout < <endl;
    cout < <*x < <endl;//输出结果错误
    }


    如上代码在一个测试函数里有一个变量 a  一个指针b 并返回指针
    在main函数里 我调用这个测试函数 并接收传回来的地址
    接收后  输出 结果正确  隔上几步在输出结果则错误
    我觉得这个是个生存周期的问题  但是又不是很理解 
    请大家指教
    我使用的是 vc6  这个是我在做题中遇到的问题里简化出来的

    比较穷 少给点分
    110  修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zcncts
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-29 23:52:011楼 得分:0
    结果图链接不上...
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • brookmill
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-30 00:14:242楼 得分:0
    不用看图了,这是个经典问题。
    函数gettest里面,变量a位于栈上,int *b=&a; 就是把b指向了栈上的一个地址。gettest退出之后,栈就被挪作它用了,里面的内容已经不由我们控制了。所以,这时候b指向的内容完全不可预料、不可信赖了,完全谈不上输出结果正确或者错误,那只是偶然现象。
    http://blog.csdn.net/xiaoxiongli/archive/2007/11/05/1868552.aspx
    http://blog.csdn.net/chenyq2008/archive/2008/09/27/2990070.aspx
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zcncts
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-30 00:31:213楼 得分:0


    这么说函数返回的指针 根本就是不可用的了?

    如果返回的是函数指针 是不是也不能用

    期待答案 我先去看看文章
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • damo_xu
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-30 01:08:214楼 得分:0
    函数可以返回指针。

    但是这个指针必须定义为 malloc或new。
    如果不是,编译器会给你警告滴!(你的程序重新编译Debug一下试试,看看它怎么警告滴?)

    不过C/C++指针有人说麻烦就在这里,这个new指针什么时候释放,就看你安排了。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zcncts
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-30 01:14:505楼 得分:0
    哦 好的 谢谢了 看了那篇文章明白了一点
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • brookmill
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-30 01:38:096楼 得分:0
    引用 3 楼 zcncts 的回复:
    这么说函数返回的指针 根本就是不可用的了?
    如果返回的是函数指针 是不是也不能用
    期待答案 我先去看看文章

    那个指针不可用,不是因为它是函数返回的,而是因为它指向了一个局部变量的地址,也就是函数的栈上,函数返回之后那块地址就不可用了。
    如4楼所说,如果函数返回的指针是malloc或new得来的,那就可以用,不过用完了要记得free或delete。
    如果函数返回的指针是其它形式的可靠的地址,那么也可以用,比如指向常量字符串的指针,等等。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • brookmill
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-30 01:44:267楼 得分:0
    建议LZ看看《高质量编程指南》的第7章尤其是7.4节,还有最后的附录B、C的试题四
    http://man.chinaunix.net/develop/c&c++/c/c.htm

    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • baihacker
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    • 4

    发表于:2008-10-30 02:02:578楼 得分:0
    #include <iostream.h>

    int* gettest()
    {
    int a=1;
    int *b=&a;
    return b;
    }
    void main()
    {
    int *x=gettest();

    cout < <*x < <endl;//输出结果 是 1  正确
    cout < <endl;
    cout < <endl;
    cout < <endl;
    cout < <endl;
    cout < <*x < <endl;//输出结果错误
    }

    现在进入
    main
    假设栈顶是esp=256,在函数调用的时候占用栈8字节.
    当前的变量分配最高位为ebp = 288
    定义一个变量,位置在ebp-4
    int *x;(x的地址为284)
    调用的时候esp = 248 (即:256-8)
    保存esp
    令ebp = 248
    esp 的值减去一个数,比如32,也主是说216到248的内存给函数gettest使用.
    变量a地址为ebp-4 = 244,值为1
    变量b地址为ebp-8 = 240,值为244 (a的地址)
    现在程序返回.
    栈恢复到
    esp = 256
    ebp = 288
    那么244赋给了main中的变量x
    endl进栈
    esp = 252
    x的值进栈:
    现在注意,内存地址为244的数据还是1,没有被改写.
    于是1进栈
    esp = 248
    调用cout的operator < <方法
    esp 减去八 等于240
    实际上在240到248的位置上是ebp的值和,函数的返回地址
    于是244内存的数据被破坏....
    ................


    这里对cout的operator < <方法依赖于实现.
    总之,内存244这个位置的数据一般说来,再次调用函数,就会被破坏.
    为了避免,在没有被破坏时,无意访问了这个内存,而让程序员误以为这些数据是可以访问的(呵,当然是可以访问的,这里是说,有没有效的问题),编译器可能在gettest返回时,把使用过的栈上的数据设置为某个特殊的值.
    所以,你就是在编译器没有做这个保护的情况下,无意中访问了,巧合...
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • killbug2004
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-30 07:54:229楼 得分:0
    局部变量是在堆栈上开辟的,堆栈上的数据没有持久性,当函数返回后,堆栈空间就有系统回收,这时函数的局部变量生命已经结束,再对其操作是没有意义的
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zmlovelx
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-30 08:15:3410楼 得分:0
    C/C++ code
    int* gettest() { int a=1; int *b=&a; return b; } void fun() { ; } void main() { int *x=gettest(); fun(); //任意一个函数调用(空函数编译器不优化)就会把那个临时变量的空间利用了 cout << hex << *x ;//输出结果错误 vc6.0是cccccccc }

    Assembly code
    int* gettest() 8: { 00401780 push ebp 00401781 mov ebp,esp 00401783 sub esp,48h 00401786 push ebx 00401787 push esi 00401788 push edi 00401789 lea edi,[ebp-48h] 0040178C mov ecx,12h 00401791 mov eax,0CCCCCCCCh 00401796 rep stos dword ptr [edi] 9: int a=1; 00401798 mov dword ptr [ebp-4],1 ;//这里是a的空间 10: int *b=&a; 0040179F lea eax,[ebp-4] 004017A2 mov dword ptr [ebp-8],eax 11: return b; 004017A5 mov eax,dword ptr [ebp-8] 12: } 13: void fun() 14: { 004017C0 push ebp 004017C1 mov ebp,esp 004017C3 sub esp,40h 004017C6 push ebx 004017C7 push esi 004017C8 push edi 004017C9 lea edi,[ebp-40h] 004017CC mov ecx,10h ;//这里占用了10h*32bits 004017D1 mov eax,0CCCCCCCCh ;//vc把这块空间全初始化为0cccccccc ;//所以在主函数中调用时把前一次函数(gettest())调用的栈内容破坏了 004017D6 rep stos dword ptr [edi] 15: ; 16: }
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • zmlovelx
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-30 08:19:5311楼 得分:0
    Assembly code
    20: int *x=gettest(); 00401808 call @ILT+45(gettest) (00401032) 0040180D mov dword ptr [ebp-4],eax 21: fun();//这里fun()函数调用的栈利用了前面a的空间了 00401810 call @ILT+500(fun) (004011f9) 22: cout << hex << *x ;
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • once_and_again
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-30 08:42:4412楼 得分:0
    引用 2 楼 brookmill 的回复:
    不用看图了,这是个经典问题。
    函数gettest里面,变量a位于栈上,int *b=&a; 就是把b指向了栈上的一个地址。gettest退出之后,栈就被挪作它用了,里面的内容已经不由我们控制了。所以,这时候b指向的内容完全不可预料、不可信赖了,完全谈不上输出结果正确或者错误,那只是偶然现象。
    http://blog.csdn.net/xiaoxiongli/archive/2007/11/05/1868552.aspx
    http://blog.csdn.net/chenyq2008/archive/2008/09/27/2990070.aspx

    高人,果然 非凡。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • rcbblgy
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-30 09:01:2013楼 得分:0
    学习了。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • ahytufc
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-30 09:30:5614楼 得分:0
    引用 2 楼 brookmill 的回复:
    不用看图了,这是个经典问题。
    函数gettest里面,变量a位于栈上,int *b=&a; 就是把b指向了栈上的一个地址。gettest退出之后,栈就被挪作它用了,里面的内容已经不由我们控制了。所以,这时候b指向的内容完全不可预料、不可信赖了,完全谈不上输出结果正确或者错误,那只是偶然现象。
    http://blog.csdn.net/xiaoxiongli/archive/2007/11/05/1868552.aspx
    http://blog.csdn.net/chenyq2008/archive/2008/09/27/2990070.aspx
    .
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • mengge
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-30 14:08:0815楼 得分:0
    int *x=gettest();
    这个就是错误的,偶尔出现“正确”结果是可能的,但是这样用迟早会出问题。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • yellowhwb
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-30 14:41:1316楼 得分:0
    [C/C++]
    int* gettest()
    {
    int a=1;
    int *b=&a;
    return b;
    }
    [C/C++]
    这个代码有问题,b指针的值是局部变量a的地址,a是存储在栈空间内的,当gettest() 结束后,a将会被释放被别人使用,所以b指向的内容自然会变化了!
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • stuarts740
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-30 18:55:3517楼 得分:0
    用指针指向临时变量,取值的时候地址已经不可用,哪怕出现正确的结果也不能相信了。
    int* gettest()
    {
      static int a=1;//将变量定义为静态的就可以了!
      int *b=&a;
      return b;
    }
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • freezezdj
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-30 20:53:2418楼 得分:0
    悬空指针问题!
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • qkhhxkj102
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-30 21:51:4719楼 得分:0
    有这事,第一次看到哦.
    那要是不用指还会那样吗
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • qkhhxkj102
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-30 21:52:1720楼 得分:0
    有这事,第一次看到哦.
    那要是不用指还会那样吗
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • T_L_Kang
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-10-30 22:55:3121楼 得分:0
    學到了不少啊,以前也碰到過類似問題,向高手致敬!!!
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • sevenhu
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-01 01:05:0922楼 得分:0
    引用 7 楼 brookmill 的回复:
    建议LZ看看《高质量编程指南》的第7章尤其是7.4节,还有最后的附录B、C的试题四
    http://man.chinaunix.net/develop/c&c++/c/c.htm


    同意。昨天刚看完这节,收获不少~~
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • jia_xiaoxin
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-01 10:40:1823楼 得分:0
    对于这道题楼主并不需要隔上几步输出同样会出现问题
    例如
    cout < <*x;
    cout < <*x < <endl;//输出结果错误
    同样会出现问题

    因为a是局部变量,它是存储在堆栈上的,在退出函数时已经失效,但是此时没有对堆栈的操作,这个局部变量的值还存在,
    经过第一个cout < <*x;之后,对堆栈进行了操作,这个局部变量的值就被刷新了。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • wenjunsu
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-01 18:29:5624楼 得分:0
    楼主加油!JF
    up
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • hqin6
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-01 18:39:4525楼 得分:0
    还有分没?
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • wmg494005678
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-01 20:24:0826楼 得分:0
    受益非浅啊....
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • shuaiwang_01
    • 等级:
    • 可用分等级:
    • 总技术分:
    • 总技术分排名:
    发表于:2008-11-12 13:41:0327楼 得分:0
    函数不要返回局部变量,会给出警告的。
    局部变量在函数调用完后就会被销毁,存放局部变量的空间已被释放。但在vc下,第一次用这个返回值的时候依旧是返回的是局部变量值(被保存了一会),但之后就会出错,因为此时你指向的内存区域是空的。