堆栈

栈中分配局部变量空间,是系统自动分配空间。定义一个 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. void Test1(void)
  6. {
  7. char *str = NULL;
  8. GetMemory1(str);
  9. strcpy(str, "hello world");
  10. printf(str);  //str一直是空,程序崩溃
  11. }

结果:

分析:

毛病出在函数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. void Test2(void)
  6. {
  7. char *str = NULL;
  8. GetMemory2(&str, 100);
  9. strcpy(str, "hello");
  10. printf(str);
  11. }

结果:输出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. void Test4(void)
  7. {
  8. char *str = NULL;
  9. str = GetMemory4();
  10. cout<< str << endl;
  11. }

结果:输出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. void main(){
  12. GetMemory6();
  13. }

结果:能够输出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的更多相关文章

  1. 彻底弄懂LSH之simHash算法

    马克·吐温曾经说过,所谓经典小说,就是指很多人希望读过,但很少人真正花时间去读的小说.这种说法同样适用于“经典”的计算机书籍. 最近一直在看LSH,不过由于matlab基础比较差,一直没搞懂.最近看的 ...

  2. 必须弄懂的495个C语言问题

    1.1 我如何决定使用那种整数类型? 如果需要大数 值(大于32, 767 或小于¡32, 767), 使用long 型.否则, 如果空间很重要(如有大数组或很多结构), 使用short 型.除此之外 ...

  3. 打工心态废掉了很多人,包括你吗?(你把现在这家公司的业务都弄清楚、弄懂了吗?君子报仇十年不晚!不离不弃!)good

    我只拿这点钱,凭什么去做那么多工作,我傻呀. 我为公司干活,公司付我一份报酬,等价交换而已,我不欠谁的. 我只要对得起这份薪水就行了,多一点我都不干,做了也白做. 工作嘛,又不是为自己干,说得过去就行 ...

  4. SQL Server-聚焦NOLOCK、UPDLOCK、HOLDLOCK、READPAST你弄懂多少?(三十四)

    前言 时间流逝比较快,博主也在快马加鞭学习SQL Server,下班回来再晚也不忘记更新下博客,时间挤挤总会有的,现在的努力求的是未来所谓的安稳,每学一门为的是深度而不是广度,求的是知识自成体系而不是 ...

  5. 彻底弄懂AngularJS中的transclusion

    点击查看AngularJS系列目录 彻底弄懂AngularJS中的transclusion AngularJS中指令的重要性是不言而喻的,指令让我们可以创建自己的HTML标记,它将自定义元素变成了一个 ...

  6. 彻底弄懂 JavaScript 执行机制

    本文的目的就是要保证你彻底弄懂javascript的执行机制,如果读完本文还不懂,可以揍我. 不论你是javascript新手还是老鸟,不论是面试求职,还是日常开发工作,我们经常会遇到这样的情况:给定 ...

  7. 彻底弄懂 Unicode 编码

    彻底弄懂 Unicode 编码 今天,在学习 Node.js 中的 Buffer 对象时,注意到它的 alloc 和 from 方法会默认用 UTF-8 编码,在数组中每位对应 1 字节的十六进制数. ...

  8. 30分钟彻底弄懂flex布局

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由elson发表于云+社区专栏 目前在不考虑IE以及低端安卓机(4.3-)的兼容下,已经可以放心使用flex进行布局了.什么是flex布 ...

  9. Golang, 以 9 个简短代码片段,弄懂 defer 的使用特点

    作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguan ...

随机推荐

  1. 在Docker运行的Nignx内部署前后端分离项目

    环境准备: Linux服务器: IP: 192.168.1.10 前端打包后的Vue项目: Port-3000, 请求地址192.168.1.10:8080 后端打包后的Java项目: Port-80 ...

  2. sonarqube 8.9版本配置收邮件提醒

    # admin登陆系统后,进入我的账户(每个用户的配置过程类似) sonarqube 8.9版本配置发信请参考我的另一篇博文: 链接如下: https://www.cnblogs.com/cndevo ...

  3. elf文件结构解读以及plt节got节的理解

    前言: 熟悉elf文件结构是一件很不错的事,因为安卓中的so加固以及修复都是需要这些知识的,包括pwn里面的rop之类的,也都是 和got节,plt节息息相关的,个人建议是在搞懂elf文件结构后,自己 ...

  4. Leetcode No.26 Remove Duplicates from Sorted Array(c++实现)

    1. 题目 1.1 英文题目 Given an integer array nums sorted in non-decreasing order, remove the duplicates in- ...

  5. 《手把手教你》系列技巧篇(八)-java+ selenium自动化测试-元素定位大法之By id(详细教程)

    1.简介 从这篇文章开始,要介绍web自动化核心的内容,也是最困难的部分了,就是:定位元素,并去对定位到的元素进行一系列相关的操作.想要对元素进行操作,第一步,也是最重要的一步,就是要找到这个元素,如 ...

  6. 【论文小综】基于外部知识的VQA(视觉问答)

    ​ 我们生活在一个多模态的世界中.视觉的捕捉与理解,知识的学习与感知,语言的交流与表达,诸多方面的信息促进着我们对于世界的认知.作为多模态领域的一个典型场景,VQA旨在结合视觉的信息来回答所提出的问题 ...

  7. Java | 标识符 & 关键字

    标识符是什么? 标识符 标识符是指在程序中,我们自己定义的内容.比如类的名字.方法的名字和变量的名字等等,都是标识符.在我们写的第一个程序当中,我们给类起名叫做Hello 也叫做标识符. 命名规则 标 ...

  8. 洛谷P5463 小鱼比可爱(加强版) 题解

    写博客不易,来玩会? 这道题我和dalao们的做法略有不同,我用的是归并排序做法qwq 归并排序求逆序对大家应该很清楚了,我这里就来讲讲如何用归并排序求出这道题的答案 让我们先观察一下规律 举个栗子, ...

  9. LeetCode解题记录(双指针专题)

    1. 算法解释 双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务.也可以延伸到多个数组的多个指针. 若两个指针指向同一数组,遍历方向相同且不会相交,则也称为滑动窗口(两个指针包围的区域 ...

  10. ERROR 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using password: NO)解决办法

    问题:ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO) 很久没用这台电脑的mysql ...