C语言内存管理

1.野指针

定义的指针变量应该初始化为NULL,用完指针后也应设置为NULL,否则该指针变量指向的是一块未知的内存,发生未知错误。

例如:

int *p = NULL;
...
...
free(p);
p = NULL;

2.栈、堆和静态区

对于程序员,我们简单的将内存理解为三部分:堆、栈、静态区。

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

堆:通过malloc系列函数或者new操作符分配的内存,生命周期由free和delete决定,手动申请,手动释放。若未释放,直到程序结束释放。特点:使用灵活,空间较大,但容易出错,未释放内存。

静态区:保存自动全局变量和static变量。静态区的内存在整个程序的生命周期都存在,在编译阶段分配。

3.常见的内存错误

3.1指针未能指向一个合法内存区域

① 结构体成员指针未初始化
struct person
{
	char *name;
	int age;
}per ,*per_s;

int main()
{
    strcpy(per.name,"lll");
    return 0;
}

此处定义了结构体变量per,只是给name指针变量分配了4个字节,但指针name没有指向一个合法的地址,在调用strcpy会将字符串"lll"向指向一个未知的地址复制,而这个未知地址,该指针没有访问权限,导致出错。

解决方案:给成员指针变量name  malloc一块空间。

相似错误,例如:

struct person
{
	char *name;
	int age;
}per ,*per_s;

int main()
{
    per_s = (struct person *)malloc(sizeof(struct person));
    strcpy(per_s->name,"lll");
    free(per_s);
    per_s = NULL;
    return 0;
}

为指针变量per_s分配了内存,但是依旧没有给name指针分配内存,此处容易产生错觉,以为给per_s分配了内存,也给name分配了内存。其解决方案同上。

例如:

int main()
{
    per_s = (struct person *)malloc(sizeof(struct person *));
    strcpy(per_s->name,"lll");
    ...
    return 0;
}

为per_s分配内存,分配的大小不合适,此处将sizeof(struct person)误写为sizeof(struct person *)。不过name指针依旧未能分配内存,解决方案同上。

③ 函数入口校验

可以通过assert宏对参数校验,例如assert(NULL != per_s);仅作为定位错误的一种方式。

3.2 分配的内存不够

为指针分配了内存,但是不够,后续操作出现越界错误。

char *p1 = "123456789";
char *p2 = (char *)malloc(sizeof(char) * strlen(p1));
strcpy(p2,p1);

p1是字符串常量,长度为9,但是占用内存大小是10字节。字符串常量的结束标志"\0",若按照上述操作,则p1的结束标志未能复制到p2。

只有字符串常量有结束标志符,下面这种写法没有:

char arr[3] = {'a','b','c'};

此外不要因为char的大小为1就省略sizeof(char)的写法,会导致代码的可移植性降低。

3.3内存越界

内存分配成功,且已经初始化,但是操作越过了内存的边界。这种错误经常是由于操作数组或指针时出现“多1”或“少1”而出现的。

3.4内存泄漏

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

因此在malloc空间,使用完成后,切记需要free释放内存,若为指针,则需要对指针初始化为NULL;若未将指针指向NULL;则成为野指针。

  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值