一定要弄懂GetMemory

2024-05-04 01:38
文章标签 一定 弄懂 getmemory

本文主要是介绍一定要弄懂GetMemory,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

堆栈

中分配局部变量空间,是系统自动分配空间。定义一个 char a;系统会自动在栈上为其开辟空间。由于栈上的空间是自动分配自动回收的,所以栈上的数据的生存周期只是在函数的运行过程中,运行后就释放掉,不可以再访问。

堆区分配程序员申请的内存空间,堆上的数据只要程序员不释放空间,就一直可以访问到,不过缺点是一旦忘记释放会造成内存泄露。

静态区是分配静态变量,全局变量空间的。

[cpp]  view plain copy
  1. int a = 0; 全局初始化区  
  2. char *p1; 全局未初始化区  
  3. main(){  
  4.      int b;      //栈  
  5.      char s[] = "abc";    //栈  
  6.      char *p2;      //栈  
  7.      char *p3 = "123456";   // 123456\0在常量区,p3在栈上。  
  8.      static int c =0;      //全局(静态)初始化区  
  9.      p1 = (char *)malloc(10);    //堆  }  
 

GetMemory1

[cpp]  view plain copy
  1. void GetMemory1(char *p)    
  2. {    
  3.     p = (char *)malloc(100);    
  4. }    
  5.     
  6. void Test1(void)    
  7. {    
  8.     char *str = NULL;    
  9.     GetMemory1(str);      
  10.     strcpy(str, "hello world");    
  11.     printf(str);  //str一直是空,程序崩溃     
  12. }    
结果:

分析:

        毛病出在函数GetMemory1 中。编译器总是要为函数的每个参数制作临时副本,指针参数p的副本是 _p,编译器使 _p = p。如果函数体内的程序修改了_p的内容,就导致参数p的内容作相应的修改。这就是指针可以用作输出参数的原因。在本例中,_p申请了新的内存,只是把 _p所指的内存地址改变了,但是p丝毫未变。所以函数GetMemory并不能输出任何东西。事实上,每执行一次GetMemory1就会泄露一块内存,因为没有用free释放内存。Test1中调用GetMemory1时,函数参数为str的副本不是str本身

GetMemory2

[cpp]  view plain copy
  1. void GetMemory2(char **p, int num)    
  2. {    
  3.     *p = (char *)malloc(num);    
  4. }    
  5.     
  6. void Test2(void)    
  7. {    
  8.     char *str = NULL;    
  9.     GetMemory2(&str, 100);    
  10.     strcpy(str, "hello");      
  11.     printf(str);        
  12. }    

结果:输出hello

分析:动态分配的内存不会自动释放;

            没有测试是否成功分配了内存,应该有if (*p == NULL) { ……} 之类的语句处理内存分配失败的其情况。

GetMemory3

[cpp]  view plain copy
  1. char * GetMemory3(void)    
  2. {      
  3.      char p[] = "hello world";    
  4.      return p;    
  5. }    
  6. void Test3(void)    
  7. {    
  8.      char *str = NULL;    
  9.      str = GetMemory3();        
  10.      printf(str);    
  11. }    
结果:输出乱码。

分析:字符数组p存在于栈空间,是局部变量,函数返回后,内存空间被释放,因此输出无效值。字符数组的值是可以修改的,例如p[0] = 't‘。

GetMemory4

[cpp]  view plain copy
  1. char *GetMemory4(void)    
  2. {    
  3.     char *p = "hello";    
  4.     return p;    
  5. }    
  6.      
  7. void Test4(void)    
  8. {    
  9.     char *str = NULL;    
  10.     str = GetMemory4();   
  11.     cout<< str << endl;    
  12. }    
结果:输出hello
分析:p指向的是字符串常量,字符串常量保存在只读的数据段,是全局区域,但不是像全局变量那样保存在普通数据段(静态存储区)。无法对p所指的内存的内容修改,例如p[0] = 'y;这样的修改是错误的。


GetMemory5

[cpp]  view plain copy
  1. char *GetMemory5(void)    
  2. {     
  3.      return "hello";    
  4. }    
  5. void Test3(void)    
  6. {    
  7.     char *str = NULL;    
  8.     str = GetMemory5();     
  9.     printf(str);    
  10. }    

结果:输出hello
分析:直接返回常量区。

GetMemory6

[cpp]  view plain copy
  1. void GetMemory6(void) {  
  2.     char *str = (char*)malloc(100);  
  3.     strcpy(str, "hello");  
  4.     free(str);  
  5.         //str = NULL,加上这句程序才不会有野指针  
  6.         if (str != NULL) {  
  7.         strcpy(str, "world");  
  8.         printf(str);  
  9.     }  
  10. }  
  11.   
  12. void main(){    
  13.     GetMemory6();  
  14. }    
结果:能够输出world,但程序存在问题。

分析:程序出现了野指针

     野指针只会出现在像C和C++这种没有自动内存垃圾回收功能的高级语言中, 所以java或c#肯定不会有野指针的概念. 当我们用malloc为一个指针分配一个空间后, 用完这个指针,把它free掉,但是没有让这个指针指向NULL或某一个特定的空间。如上面程序一样,将str进行free后,只是释放了指针所指的内存,但指针并没有释放掉,此时指针所指的是垃圾内存;这样的话,if语句永为真,if判断无效。delete也存在同样的问题。

      防止产生野指针:(1)指针变量一定要初始化为NULL,因为任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的。(2)当free或delete后,将指针指向NULL。通常判断一个指针是否合法,都是使用if语句测试该指针是否为NULL。

原文:http://blog.csdn.net/u013074465/article/details/42784267

这篇关于一定要弄懂GetMemory的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/958078

相关文章

跟我一起玩《linux内核设计的艺术》第1章(四)——from setup.s to head.s,这回一定让main滚出来!(已解封)

看到书上1.3的大标题,以为马上就要见着main了,其实啊,还早着呢,光看setup.s和head.s的代码量就知道,跟bootsect.s没有可比性,真多……这确实需要包括我在内的大家多一些耐心,相信见着main后,大家的信心和干劲会上一个台阶,加油! 既然上篇已经玩转gdb,接下来的讲解肯定是边调试边分析书上的内容,纯理论讲解其实我并不在行。 setup.s: 目标:争取把setup.

图解!24张图彻底弄懂九大常见数据结构!(转)

对于学习数据结构,打牢基础的小伙伴来说,是篇相当棒的文章,值得学习 文章链接:图解!24张图彻底弄懂九大常见数据结构! 事情发展就是这样,也许很啰嗦。 大致就是公司A(工作4年7个月)-->B(试用期2星期)-->C(3月20日至今)。B公司开始挖我。 纠结

你一定不知道的10个Python读写文件的高效技巧!

在Python中高效地读写文件是日常编程任务中的一项重要技能。这里将详细介绍10个高效的Python文件读写技巧,涵盖基本的文件操作到高级技巧。 1. 使用with语句管理文件 使用with语句可以确保文件被正确关闭,即使在读写文件时发生异常也是如此。with语句会自动管理文件的上下文,包括文件的打开和关闭。 with open('example.txt', 'r') as file:con

学历不会改变命运但知识一定可以改变命运

一、知识与学历的区别 首先,我们需要区分“知识”与“学历”。学历通常是指一个人通过正规教育体系获得的证书或学位,而知识则是更为宽泛的概念,它包括了一个人通过各种途径获得的信息、技能和理解。学历可能只是知识的一部分,而真正的知识应该是全面的,它不仅仅局限于书本和课堂。 二、知识如何改变命运 提升个人素质:知识的积累能够提升个人素质,包括思维能力、判断力和创造力。这些都是在现代社会中取得成功

【编程底层思考】线程阻塞时一定会释放cpu吗

线程阻塞时是否释放CPU取决于阻塞的原因和操作系统的行为。以下是一些具体情况: 1. 阻塞等待资源:当线程因为等待某个资源(如锁、信号量、条件变量等)而阻塞时,它通常会释放CPU,以便其他线程可以运行。在这种情况下,阻塞的线程不会占用CPU资源,直到它等待的资源变得可用。 2. 阻塞等待I/O操作:当线程因为等待I/O操作(如读取文件、网络通信等)而阻塞时,它也会释放CPU。操作系统会将线程挂

连接oracle的应用达到一定数量其他人就无法连接的原因以及解决办法

根本原因就是Oracle的process和session已经达到了甚至超过了最大值,解决办法如下: 查看process和session的参数和占用值: show parameter processes; select count() from v p r o c e s s ; s e l e c t c o u n t ( ∗ ) f r o m v process; select count(

SAT作文例子一定要鲜活

很多学生都问,在SAT作文例子中使用外国的还是中国的例子好,自己也曾听从过老师的教诲:对于barron’s里面作文讲的X大最常见话题(貌似有:obstacle, courage, equality等,每个方面找10个很有说服力的SAT作文例子。于是自己开始疯狂地寻找例子的历程,结果过去了一个月,例子找到10来个有力的(离要求还差很远,但是在SAT作文中就是运用不上去。   SAT作文例子一定

你一定想知道的Redis数据库详解

目录 一、Redis介绍 1.1定义 1.2为什么要有Redis 1.3 Redis和Mysql的对比 1.4 Redis的一些常见命令 二、Redis 常见的数据结构 一、字符串(String) 二、哈希(Hash) 三、列表(List) 四、集合(Set) 五、有序集合(Sorted Set) 三、Redis的应用场景 四、实验练习 4.1redis部署 实验环境

【劳动仲裁】打工人一定要看这篇文章【收藏篇】

【劳动仲裁】纯经验干货分享,点个关注防止需要时找不到! 当公司决定搞你心态,变相逼退你时,无非就那么些手段,只要你能正确应对,并做好收集证据的准备,就不足为惧。合理利用法律的武器维护自身利益。 什么情况是N ?2N?N+1? N 指的是公司有违法行为(社保未全额缴纳,未足额发放工资,不提供 劳动条件,合同到期不续签,公司破产清算),员工提出被迫离职 ,解除劳动合同经济补偿金 (金额:离

HashMap原理。图文并茂式解读。这些注意点你一定还不了解

[TOC] 概述 本篇文章我们来聊聊大家日常开发中常用的一个集合类 - HashMap。HashMap 最早出现在 JDK 1.2中,底层基于散列算法实现。HashMap 允许 null 键和 null 值,在计算哈键的哈希值时,null 键哈希值为 0。HashMap 并不保证键值对的顺序,这意味着在进行某些操作后,键值对的顺序可能会发生变化。另外,需要注意的是,HashMap 是非线程安全