【C语言深度学习】阅读笔记 内存管理

一、内存三大块

静态区:保存自动全局变量和 static 变量(包括 static 全局和局部变量)。静态区的内容在总个程序的生命周期内都存在,由编译器在编译的时候分配。

栈:保存局部变量。栈上的内容只在函数的范围内存在,当函数运行结束,这些内容也会自动被销毁。其特点是效率高,但空间大小有限。

堆:由 malloc 系列函数或 new 操作符分配的内存。其生命周期由 free 或 delete 决定。在没有释放之前一直存在,直到程序结束。其特点是使用灵活,空间比较大,但容易出错。

二、常见的内存错误及解决办法

1.指针没有指向一块合法的内存

struct student

{

 char *name;

int score;

 }stu,*pstu;

这里的name没有分配内存,解决办法为 name 指针 malloc 一块空间

函数入口的检验:

一般在函数入口处使用 assert(NULL != p)对参数进行校验。在非参数的地方使用if(NULL != p)来校验。

assert 是一个宏,而不是函数,包含在 assert.h 头文件中。如果其后面括号里的值为假,则程序终止运行,并提示出错;如果后面括号里的值为真,则继续运行后面的代码。这个宏只在 Debug 版本上起作用,而在 Release 版本被编译器完全优化掉,这样就不会影响代码的性能。assert 宏可以帮助我们定位错 误,而不是排除错误。

2.为指针分配的内存太小

为指针分配了内存,但是内存大小不够,导致出现越界错误。

char *p1 = “abcdefg”;

char *p2 = (char *)malloc(sizeof(char)*strlen(p1));

strcpy(p2,p1);

 p1 字符串中最后一个空字符“\0”没有被拷贝到 p2 中,应改为char *p2 = (char *)malloc(sizeof(char)*strlen(p1)+1*sizeof(char))

3.内存分配成功,但并未初始化

int i = 10; char *p = (char *)malloc(sizeof(char));

int i = 0; char *p = NULL;这种形式更好,上面一种不能确定变量的初始值

int a[10] = {0}; 或者用 memset 函数来初始化为 0: memset(a,0,sizeof(a))

4.内存越界

例如:

int a[10] = {0}; for (i=0; i<=10; i++)//for 循环的循环变量一定要使用半开半闭的区间

5.内存泄漏

会产生泄漏的内存就是堆上的内存(这里不讨论资源或句柄等泄漏情况),也就是说由 malloc 系列函数或 new 操作符分配的内存。如果用完之后没有及时 free 或 delete,这块内存就无法释放,直到整个程序终止。

malloc 函数

malloc函数参数为int类型,即申请分配的内存大小,单位为byte,函数返回这块内存的首地址,返回值为void类型的指针,因此需要强转为我们需要的类型,如

Char *p=(char*)malloc(100);

如果所申请的内存块大于目前堆上剩余内存块(整块),则内存分配会失败,函数返回 NULL。必须用 if(NULL != p)语句来验证内存确实分配成功了

用 malloc 函数申请 0 字节内存,会返回一个正常的地址,但无法使用该内存

内存释放free(p)传进去的参数就是所要释放的内存块的首地址。free作用:斩断指针变量与该块内存的关系,内存上的值不会有变化

malloc 两次只 free 一次会内存泄漏;malloc 一次 free 两次肯定会出错。也就是说,在程序 中 malloc 的使用次数一定要和 free 相等

易错点:内存已经被释放,但仍然使用指针:

①用完free之后,没有重新p=NULL。导致下次无法使用if(NULL != p)的校验语句

②函数返回栈内存 

比如在函数内部定义了一个数组,却用 return 语句返回指向该数组的指针。

③内存使用太复杂,弄不清到底哪块内存被释放,哪块没有被释放。

1.指针没有指向一块合法的内存

struct student

{

 char *name;

int score;

 }stu,*pstu;

这里的name没有分配内存,解决办法为 name 指针 malloc 一块空间

函数入口的检验:

一般在函数入口处使用 assert(NULL != p)对参数进行校验。在非参数的地方使用if(NULL != p)来校验。

assert 是一个宏,而不是函数,包含在 assert.h 头文件中。如果其后面括号里的值为假,则程序终止运行,并提示出错;如果后面括号里的值为真,则继续运行后面的代码。这个宏只在 Debug 版本上起作用,而在 Release 版本被编译器完全优化掉,这样就不会影响代码的性能。assert 宏可以帮助我们定位错 误,而不是排除错误。

2.为指针分配的内存太小

为指针分配了内存,但是内存大小不够,导致出现越界错误。

char *p1 = “abcdefg”;

char *p2 = (char *)malloc(sizeof(char)*strlen(p1));

strcpy(p2,p1);

 p1 字符串中最后一个空字符“\0”没有被拷贝到 p2 中,应改为char *p2 = (char *)malloc(sizeof(char)*strlen(p1)+1*sizeof(char))

3.内存分配成功,但并未初始化

int i = 10; char *p = (char *)malloc(sizeof(char));

int i = 0; char *p = NULL;这种形式更好,上面一种不能确定变量的初始值

int a[10] = {0}; 或者用 memset 函数来初始化为 0: memset(a,0,sizeof(a))

4.内存越界

例如:

int a[10] = {0}; for (i=0; i<=10; i++)//for 循环的循环变量一定要使用半开半闭的区间

5.内存泄漏

会产生泄漏的内存就是堆上的内存(这里不讨论资源或句柄等泄漏情况),也就是说由 malloc 系列函数或 new 操作符分配的内存。如果用完之后没有及时 free 或 delete,这块内存就无法释放,直到整个程序终止。

malloc 函数

malloc函数参数为int类型,即申请分配的内存大小,单位为byte,函数返回这块内存的首地址,返回值为void类型的指针,因此需要强转为我们需要的类型,如

Char *p=(char*)malloc(100);

如果所申请的内存块大于目前堆上剩余内存块(整块),则内存分配会失败,函数返回 NULL。必须用 if(NULL != p)语句来验证内存确实分配成功了

用 malloc 函数申请 0 字节内存,会返回一个正常的地址,但无法使用该内存

内存释放free(p)传进去的参数就是所要释放的内存块的首地址。free作用:斩断指针变量与该块内存的关系,内存上的值不会有变化

malloc 两次只 free 一次会内存泄漏;malloc 一次 free 两次肯定会出错。也就是说,在程序 中 malloc 的使用次数一定要和 free 相等

易错点:内存已经被释放,但仍然使用指针:

①用完free之后,没有重新p=NULL。导致下次无法使用if(NULL != p)的校验语句

②函数返回栈内存 

比如在函数内部定义了一个数组,却用 return 语句返回指向该数组的指针。

③内存使用太复杂,弄不清到底哪块内存被释放,哪块没有被释放。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值