内存管理学习笔记

1.栈、堆和静态区
静态区:保存自动全局变量和static变量(包括全局静态变量和局部静态变量)。静态区的内容在整个程序的生命周期内都存在。
栈:保存局部变量。栈上的内容只在函数的范围内存在,当函数运行结束,这些内容也会自动被销毁。其特点是效率高,但是空间大小有限。
堆:由malloc系列函数或new操作符分配的内存。其生命周期由free或delete决定。在没有释放之前一直存在,直到程序结束。其特点是使用灵活,空间比较大,但容易出错。
2.常见的内存错误以及对策
2.1指针没有指向一块合法的内存
定义了指针变量,但是没有为指针分配内存,即指针没有指向一块合法的内存。

2.1.1结构体成员指针未初始化
struct student{
	char *name;
	int score;
}stu,*pstu;
int main(void)
{
	strcpy(stu.name, "Jimy");
	stu.score = 99;
	return 0;
}
定义了结构体变量stu,但是它没有想到这个结构体内部char * name这个成员在定义结构体变量stu时,只是给name这个指针变量本身分配了4个字节。name指针并没有指向一个合法的地址,这时候其内部存的只是一些乱码。所在在调用strcpy函数时,会出现段错误。
解决办法是需要name分配空间。
struct student{
	char *name;
	int score;
}stu,*pstu;
int main(void)
{
	pstu = (struct student *)malloc(sizeof(struct student));
	strcpy(pstu->name, "Jimy");
	stu->score = 99; free(pstu);
	return 0;
}
上面也是只给pstu分配了空间,而没有给name分配空间,同样会出现错误。
正确的实例:
struct student{
	char *name;
	int score;
}stu,*pstu;
int main(void)
{
	pstu = (struct student *)malloc(sizeof(struct student));
	pstu->name = (char *)malloc(10*sizeof(char));
	strcpy(pstu->name, "Jimy");
	pstu->score = 99;
	free(pstu->name);
	pstu->name = NULL;
	free(pstu);
	pstu = NULL;
	return 0;
}
2.1.2 没有为结构体指针分配足够的内存

struct student{
	char *name;
	int score;
}stu,*pstu;
int main(void)
{
	pstu = (struct student *)malloc(sizeof(struct student*));
	strcpy(pstu->name, "Jimy");
	pstu->score = 99;
	free(pstu);
	return 0;
}
为pstu分配内存的时候,分配的内存大小不合适。这里把sizeof(struct student)误写为sizeof(struct student *),当然name也没有被分配空间,拷贝的时候肯定会出错。

2.1.3 函数的入口校验
不管什么时候,我们使用指针之前一定要确保指针是有效的。
2.2 为指针分配的内存太小
为指针分配了内存,但是内存大小不够,代指出现越界错误。
char *p1 = "abcdgeg";
char *p2 = (char *)malloc(sizeof(char)*strlen(p1));
strcpy(p2,p1);
p1是字符串常量,其长度是7个字符,但其所占内存大小为8个byte。字符串常量的结束标志是'\0'。这样的话,将导致p1字符串常量最后一个空字符没有被拷贝到p2中,解决的办法是加上这个字符串结束标志符。
char *p2 = (char *)malloc(sizeof(char)*strlen(p1) + 1*sizeof(char));
注意:只有字符串常量才有结束标志符。

2.3 内存分配成功,但并未初始化
int i=10;
char *p = (char*)malloc(sizeof(char));
在我们还不确定这个变量的初值时,可以将其初始化为0或者NULL。
int i=0;
char *p = NULL;
定义了数组的话,可以这样初始化:
int a[10] = {0};
或者使用memset函数,memset(a,0,sizeof(a));
如果指针变量未被初始化,会导致if语句或者assert语句校验失败。
2.4 内存越界
内存分配成功,且已经初始化,但是操纵越过了内存的边界。
2.5内存泄露
内存泄露是很难避免的。会产生泄露的内存就是堆上的内存,也就是由malloc系列函数分配的内存。如果用完没有及时free或
delete,这块内存就无法释放,知道整个程序终止。

2.5.1如果使用malloc
(void *)malloc(int size);
malloc函数的返回值是一个void类型的指针,参数为int类型数据,即申请分配的内存大小,单位是byte。内存分配成功之后,
malloc函数返回这块内存的首地址。你需要一个指针来接收这个地址。但是由于malloc返回值是void*类型的,所以必须强制转换成
你所接收的类型。也就是说这块内存将要用来存储什么类型的数据。
分配完成之后需要检验是否分配成功。
if(NULL != p)
2.5.2 内存释放
free(p);
free函数就做了一件事:斩断指针变量与这块内存的关系。
我们可以说malloc函数分配的内存块是属于p的,因为我们对这块内存的访问都需要通过p来进行。free函数就是把这块内
存和p之间的所有关系斩断。从此p和哪块内存之间的所有关系斩断。至于指针变量p本身保存的地址并没有改变,但是它对这个地址
处的哪块内存却已经没有所有权了。那块被释放的内存里面保存的值也没有改变,只是再也没有办法使用了。
malloc与free配对使用,不然肯定出错。
2.5.3内存释放之后
既然free函数之后指针变量p本身保存的地址并没有改变,哪我们就需要重新把p的值变为NULL;
释放完了指针,一定要设置指针为NULL。

2.5.4 内存已经被释放了,但是继续通过指针来使用
一般有三种情况:
1.就是free(p)之后,继续通过p指针来访问内存。解决办法就是给p设置为NULL。
2.函数返回栈内存。比如在函数内部定义了一个数组,却用return语句返回指向该数组的指针。
3.内存使用太复杂,弄不清哪块内存被释放了,哪块内存没有被释放。解决的办法是重新设计程序,改善对象之间的调用关系。









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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值