热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

探讨一个可能被认为不太体面的问题

如下程序#include<iostream>classA{public:char*test();private:
 
 如下程序

#include 
class A
{
  public :
        char * test();
private:
        char *m;
};

char * A::test()
{
   m = "1234567890";
}

char * test()
{
   char *m = "0987654321";
}

void main()
{
   A a;
  char * m = a.test();
 std::cout << m;                            //函数生命周期结束了,栈区数据怎么还在,我靠,没出问题? 以前一直用智能指针,没在意这个,今天看代码发现这么个问题;

    m = test();                                 //函数生命周期结束了,栈区数据怎么还在,我靠,没出问题? 以前一直用智能指针,没在意这个,今天看代码发现这么个问题;
  std::cout < }







 
  这问题有点掉价啊.....

30 个解决方案

#1


"1234567890"
这种字符串直接量是在常量区的, 这个数据不会丢失的.
我觉得略奇特的是, 你不觉得你的test没有return语句么?

#2


你的m是一个main里的指针,main还没有结束啊,
函数结束,又不会改变m指向的内存的数据,
还有一点,你命名能养成好的习惯吗?

#3


纯在网页手打而已.....不是跑过的,随手敲一遍而已

#4


随手测试,,,10s乱敲完的

#5


函数结束,栈数据清除,m的确还指那………但是那快内存已经给系统了

#6


好像test()没有返回值啊,这样怎么给m赋值呢?

#7


引用 5 楼 luoxuechengbing 的回复:
函数结束,栈数据清除,m的确还指那………但是那快内存已经给系统了

那块数据没给系统, 因为你是用的"1234567890"这种形式, 它是在常量区, 你程序退出的时候才会回收:
http://blog.csdn.net/xcyuzhen/article/details/4543264

#8


生命周期结束了,但是数据还是在那个地方的。指针销毁了而已吧?但是地址已经传递出去了,no problem

#9


你这是在常量区域
执行一次后,就在那里待着了
到程序结束吧

#10


数据在说明栈还没有被重新使用,不代表这样就是安全的吧

#11


该回复于2014-08-06 17:27:53被管理员删除

#12


引用 9 楼 henry3695 的回复:
你这是在常量区域
执行一次后,就在那里待着了
到程序结束吧


  不应该是这样的,  你可以试试一个数组... 一样也在 ...
     我的回答是 和  10L星哥一样的,不安全...    

#13


引用 9 楼 henry3695 的回复:
你这是在常量区域
执行一次后,就在那里待着了
到程序结束吧


的确是常量了。。。。但是 能给点资料吗  
  常量类型的为什么要等到程序结束才会释放?

#14


引用 12 楼 luoxuechengbing 的回复:
Quote: 引用 9 楼 henry3695 的回复:

你这是在常量区域
执行一次后,就在那里待着了
到程序结束吧


  不应该是这样的,  你可以试试一个数组... 一样也在 ...
     我的回答是 和  10L星哥一样的,不安全...    


是的, 数组也可能在, 你那个字符串直接量是在常量区没有错, 同样的现象不同的道理.
在栈里局部变量退出的时候只是改栈指针而已, 之前的数据不会主动覆盖, 不安全.
但你的程序里的那个m指针, 是安全的. 不冲突

#15


引用 14 楼 wanght99 的回复:
Quote: 引用 12 楼 luoxuechengbing 的回复:

Quote: 引用 9 楼 henry3695 的回复:

你这是在常量区域
执行一次后,就在那里待着了
到程序结束吧


  不应该是这样的,  你可以试试一个数组... 一样也在 ...
     我的回答是 和  10L星哥一样的,不安全...    


是的, 数组也可能在, 你那个字符串直接量是在常量区没有错, 同样的现象不同的道理.
在栈里局部变量退出的时候只是改栈指针而已, 之前的数据不会主动覆盖, 不安全.
但你的程序里的那个m指针, 是安全的. 不冲突



  为什么常量区的数据就不会结束呢?  百度了下,看到资料说是拷贝了份,这个时候栈区只是存在了一个地址了~!

#16


其实电脑开机后物理内存的每个字节都是可读写的,区别仅在于操作系统内存管理模块在你读写时是否能发现并是否采取相应动作而已。操作系统管理内存的粒度不是字节而是页,一页通常为4KB。

#17


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

对学习编程者的忠告:
眼过千遍不如手过一遍!
书看千行不如手敲一行!
手敲千行不如单步一行!
单步源代码千行不如单步对应汇编一行!

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对应的汇编并单步执行观察相应内存和寄存器变化。)

#18


引用 15 楼 luoxuechengbing 的回复:
Quote: 引用 14 楼 wanght99 的回复:

Quote: 引用 12 楼 luoxuechengbing 的回复:

Quote: 引用 9 楼 henry3695 的回复:

你这是在常量区域
执行一次后,就在那里待着了
到程序结束吧


  不应该是这样的,  你可以试试一个数组... 一样也在 ...
     我的回答是 和  10L星哥一样的,不安全...    


是的, 数组也可能在, 你那个字符串直接量是在常量区没有错, 同样的现象不同的道理.
在栈里局部变量退出的时候只是改栈指针而已, 之前的数据不会主动覆盖, 不安全.
但你的程序里的那个m指针, 是安全的. 不冲突



  为什么常量区的数据就不会结束呢?  百度了下,看到资料说是拷贝了份,这个时候栈区只是存在了一个地址了~!

因为m是指针, 字符串常量是编译时就确定的, 可以理解为编译时专门为它分配了空间, 程序里给m赋值的时候就是让m指向它..
给m赋值的时候关于那个字符串没有任何分配空间的动作. 当然也就无从回收.

#19


…………我不是这个意思,可能我表达错误………我就是想说,常量的数据保存在哪里. 栈上只有常量的地址了!!!!

#20


汇编代码:

12:       m = "1234567890";
0040116D   mov         eax,dword ptr [ebp-4]
00401170   mov         dword ptr [eax],offset string "1234567890" (0043201c)

18:       char *m = "0987654321";
004011A8   mov         dword ptr [ebp-4],offset string "0987654321" (0043202c)

返回的是内存中的这两个地址:
0043202c
0043201c
只要内存中这两个地址中的内容没有销毁,那么,这个值就一直可以用。

#21


引用 19 楼 luoxuechengbing 的回复:
…………我不是这个意思,可能我表达错误………我就是想说,常量的数据保存在哪里. 栈上只有常量的地址了!!!!

如果是VC的话,跟踪的时候,按ALT+8,看汇编代码。里面有常量的地址。
然后ALT+6,可以看相应内存地址的内容。

#22


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

对学习编程者的忠告:
眼过千遍不如手过一遍!
书看千行不如手敲一行!
手敲千行不如单步一行!
单步源代码千行不如单步对应汇编一行!

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对应的汇编并单步执行观察相应内存和寄存器变化。)


不变应万变的赵老师好

   答案我找到了:http://blog.chinaunix.net/uid-25002135-id-2974174.html

#23


引用 21 楼 zjq9931 的回复:
Quote: 引用 19 楼 luoxuechengbing 的回复:

…………我不是这个意思,可能我表达错误………我就是想说,常量的数据保存在哪里. 栈上只有常量的地址了!!!!

如果是VC的话,跟踪的时候,按ALT+8,看汇编代码。里面有常量的地址。
然后ALT+6,可以看相应内存地址的内容。


引用 18 楼 wanght99 的回复:
Quote: 引用 15 楼 luoxuechengbing 的回复:

Quote: 引用 14 楼 wanght99 的回复:

Quote: 引用 12 楼 luoxuechengbing 的回复:

Quote: 引用 9 楼 henry3695 的回复:

你这是在常量区域
执行一次后,就在那里待着了
到程序结束吧


  不应该是这样的,  你可以试试一个数组... 一样也在 ...
     我的回答是 和  10L星哥一样的,不安全...    


是的, 数组也可能在, 你那个字符串直接量是在常量区没有错, 同样的现象不同的道理.
在栈里局部变量退出的时候只是改栈指针而已, 之前的数据不会主动覆盖, 不安全.
但你的程序里的那个m指针, 是安全的. 不冲突



  为什么常量区的数据就不会结束呢?  百度了下,看到资料说是拷贝了份,这个时候栈区只是存在了一个地址了~!

因为m是指针, 字符串常量是编译时就确定的, 可以理解为编译时专门为它分配了空间, 程序里给m赋值的时候就是让m指向它..
给m赋值的时候关于那个字符串没有任何分配空间的动作. 当然也就无从回收.


引用 10 楼 starytx 的回复:
数据在说明栈还没有被重新使用,不代表这样就是安全的吧



http://blog.chinaunix.net/uid-25002135-id-2974174.html找到答案了哈~!

#24


引用 23 楼 luoxuechengbing 的回复:
Quote: 引用 21 楼 zjq9931 的回复:

Quote: 引用 19 楼 luoxuechengbing 的回复:

…………我不是这个意思,可能我表达错误………我就是想说,常量的数据保存在哪里. 栈上只有常量的地址了!!!!

如果是VC的话,跟踪的时候,按ALT+8,看汇编代码。里面有常量的地址。
然后ALT+6,可以看相应内存地址的内容。


引用 18 楼 wanght99 的回复:
Quote: 引用 15 楼 luoxuechengbing 的回复:

Quote: 引用 14 楼 wanght99 的回复:

Quote: 引用 12 楼 luoxuechengbing 的回复:

Quote: 引用 9 楼 henry3695 的回复:

你这是在常量区域
执行一次后,就在那里待着了
到程序结束吧


  不应该是这样的,  你可以试试一个数组... 一样也在 ...
     我的回答是 和  10L星哥一样的,不安全...    


是的, 数组也可能在, 你那个字符串直接量是在常量区没有错, 同样的现象不同的道理.
在栈里局部变量退出的时候只是改栈指针而已, 之前的数据不会主动覆盖, 不安全.
但你的程序里的那个m指针, 是安全的. 不冲突



  为什么常量区的数据就不会结束呢?  百度了下,看到资料说是拷贝了份,这个时候栈区只是存在了一个地址了~!

因为m是指针, 字符串常量是编译时就确定的, 可以理解为编译时专门为它分配了空间, 程序里给m赋值的时候就是让m指向它..
给m赋值的时候关于那个字符串没有任何分配空间的动作. 当然也就无从回收.


引用 10 楼 starytx 的回复:
数据在说明栈还没有被重新使用,不代表这样就是安全的吧



http://blog.chinaunix.net/uid-25002135-id-2974174.html找到答案了哈~!

支持分享。

#25


引用 1 楼 wanght99 的回复:
"1234567890"
这种字符串直接量是在常量区的, 这个数据不会丢失的.
我觉得略奇特的是, 你不觉得你的test没有return语句么?


+1

确定程序能编译通过?

#26


  什么鸡巴玩意

#27


C/C++编译的程序占用的内存分为以下几个区域:

1、栈区(stack)

由系统自动分配和释放,用于存放函数的参数值,局部变量值等。其在内存中是一块连续的存储区域,由低地址向高地址延伸。

2、堆区(heap) 

由程序员分配和释放,若程序员不释放,则程序结束时可能由操作系统回收。其存储空间在内存中是不连续,分配方式类似于链表。 

3、静态区(static)

又称全局区,程序结束后由系统释放,用于存放全局变量和静态变量。初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量则存储在相邻的另一块区域。 

4、文字常量区

程序结束后由系统释放,用于存储常量,字符串常量就是放在这里的。


5、程序代码区

存放函数体的二进制代码。 

很明显,你的数据是存放在常量区的,程序结束后才会有系统释放。

#28


因为 返回值,往往通过寄存器传递。
你的函数 没写return 语句,返回值差不多就是 寄存器中残留的值
其实,也就是执行  m= "0123456789"  的时候,地址 m的值残留到寄存器中了,
因为表达式求值,也可能会使用这个寄存器
,,,,VC,本机代码,X86,32Bits 这个寄存器是 eax
具体,可以查看对应的汇编代码。


在编译器中,可以设置警告以及错误等级,等等编译选项
随着编译选项的设置不同,编译结果不尽相同
通常,这种不写return语句的函数,会有警告或者出错信息。

另外,release 版本,test() 后面的输出语句,可能会输出不确定的结果。

因为 代码char *m = "0987654321";
对于 test()属于无用代码,优化时,可以直接忽略,不生成任何代码。

建议,每个带返回值的函数,都要写return语句。
多分支返回的函数,一定不要忘记写最后的那个return语句。

#29


有返回值的函数,应该明确写上return 语句,不然结果是不确定的.

#30


,也就是执行 m= "0123456789"  的时候,"0123456789" 的地址,
 即(指针)m的值,残留在寄存器中,函数调用结束后,得到的是寄存器中的值,
也就是函数内部,表达式m= "0123456789" 计算的残留的值。

PS:
记住,如果非构造函数,没有写return 语句 ,通常函数返回值。
就是计算的中间结果,残留在寄存器中的值,
根据返回值类型不同,硬件系统,操作系统,
还有编译器的不同等等,结果可能是不同的。
一句话,结果不确定


推荐阅读
  • 本文探讨了 C++ 中普通数组和标准库类型 vector 的初始化方法。普通数组具有固定长度,而 vector 是一种可扩展的容器,允许动态调整大小。文章详细介绍了不同初始化方式及其应用场景,并提供了代码示例以加深理解。 ... [详细]
  • 本文总结了2018年的关键成就,包括职业变动、购车、考取驾照等重要事件,并分享了读书、工作、家庭和朋友方面的感悟。同时,展望2019年,制定了健康、软实力提升和技术学习的具体目标。 ... [详细]
  • 本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • C++实现经典排序算法
    本文详细介绍了七种经典的排序算法及其性能分析。每种算法的平均、最坏和最好情况的时间复杂度、辅助空间需求以及稳定性都被列出,帮助读者全面了解这些排序方法的特点。 ... [详细]
  • 题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ... [详细]
  • CentOS7源码编译安装MySQL5.6
    2019独角兽企业重金招聘Python工程师标准一、先在cmake官网下个最新的cmake源码包cmake官网:https:www.cmake.org如此时最新 ... [详细]
  • 深入理解 SQL 视图、存储过程与事务
    本文详细介绍了SQL中的视图、存储过程和事务的概念及应用。视图为用户提供了一种灵活的数据查询方式,存储过程则封装了复杂的SQL逻辑,而事务确保了数据库操作的完整性和一致性。 ... [详细]
  • 数据库内核开发入门 | 搭建研发环境的初步指南
    本课程将带你从零开始,逐步掌握数据库内核开发的基础知识和实践技能,重点介绍如何搭建OceanBase的开发环境。 ... [详细]
  • 在前两篇文章中,我们探讨了 ControllerDescriptor 和 ActionDescriptor 这两个描述对象,分别对应控制器和操作方法。本文将基于 MVC3 源码进一步分析 ParameterDescriptor,即用于描述 Action 方法参数的对象,并详细介绍其工作原理。 ... [详细]
  • 本章将深入探讨移动 UI 设计的核心原则,帮助开发者构建简洁、高效且用户友好的界面。通过学习设计规则和用户体验优化技巧,您将能够创建出既美观又实用的移动应用。 ... [详细]
  • 本文详细介绍了macOS系统的核心组件,包括如何管理其安全特性——系统完整性保护(SIP),并探讨了不同版本的更新亮点。对于使用macOS系统的用户来说,了解这些信息有助于更好地管理和优化系统性能。 ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • 题目Link题目学习link1题目学习link2题目学习link3%%%受益匪浅!-----&# ... [详细]
  • C++构造函数与初始化列表详解
    本文深入探讨了C++中构造函数的初始化列表,包括赋值与初始化的区别、初始化列表的使用规则、静态成员初始化等内容。通过实例和调试证明,详细解释了初始化列表在对象创建时的重要性。 ... [详细]
author-avatar
菜鸟自学编程
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有