动态内存分配

本文详细介绍了C语言中的内存区域,包括栈区、堆区和静态区,以及动态内存分配的函数malloc、calloc、realloc和free的使用。强调了动态内存分配中的注意事项,如内存泄漏、空指针解引用、越界访问等问题,并提醒程序员在使用动态内存后要确保正确释放。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在谈到动态内存分配之前我们就要谈谈C语言中的内存分配了:栈区 堆区 静态区。

栈区(stack):局部变量、函数的形参存储(自动,连续的内存)出了作用域内存释放。

静态区(static):全局变量、static(关键字)修饰的静态变量存储,在程序的整个生命周期都存在,程序结束,内存自动释放。

堆区(heap):动态存储(非常大的内存池,非连续分配)可以自己分配任意大小的空间(不要超出最大空间范围),但要及时释放(手动),如果在变量使用结束时释放内存失败(未释放)或程序不结束的话会造成内存泄漏,即内存仍然被占用,不能被其它进程获取。

动态内存分配的时候就要自己分配空间(malloc  calloc  realloc)自己使用,用完自己释放掉(free)那么接下来就开始动态内存分配咯!


free

free 函数无返回值,参数是一个指针变量,该指针变量指向的空间正是你动态开辟的空间

如果该指针变量存的是空指针(NULL),则free函数释放该空间时啥都不做,但是如果不是空的话,free函数,作用是释放内存,内存释放是标记删除, 只会修改当前空间的所属状态,并不会清除空间内容,即:

 


malloc

认识

该函数的功能就是开辟一个空间,参数是你要分配的空间大小(字节为单位),返回值是一个指针(任意类型),如果成功开辟好空间就返回该空间的起始地址,如果开辟空间失败就返回空指针(NULL)。

举例 

 // 博主使用的是 x64 环境,所以地址看着会长一些。

提一点:如果开辟空间为0的话,标准并未定义该情况,产生的效果取决于编译器。

使用(浅用)


 calloc

 认识

 该函数的功能是开辟一个已经初始化为0的空间,返回值和 malloc 一样,参数一个是元素的个数,另一个是每个元素的大小。

举例使用

 calloc 和 malloc 函数的区别:

  1. 参数不同
  2. malloc 在堆区开辟空间时不会初始化,calloc 在堆区开辟空间时会将每个字节初始化为0。


 realloc

认识

 该函数的功能是改变已有的动态内存块的空间大小(也许是开辟一个新的空间),返回值也是一个指针,参数一是要改变的已有动态内存空间,参数二是最终的空间大小。

如果 realloc 函数的第一个参数是NULL的话,此时realloc函数的功能就相当于是malloc一样

举例

int main()
{
	int* p = (int*)malloc(3 * sizeof(int));
	assert(p);
	int i = 0;
	for (i = 0; i < 3; i++)//赋值
	{
		p[i] = i + 1;
	}

	//想要开辟的空间不够用了,要扩容到5个
	int* q = (int*)realloc(p, 20);
	assert(q);//判断空间是否扩容成功
	if (p != q)//不相等的话
	{
		p = q;//将q的值赋给p
	}
    //赋值打印
    for (i = 3; i < 5; i++)
    {
		p[i] = i + 1;
	}
	for (i = 0; i < 5; i++)
	{
		printf("%d ", p[i]);
	}
	
	free(p);
	p = NULL;

	return 0;
}

 这里可以看出 realloc 在扩容时,同时将原数据也一并拷贝了过来,所以我后面对扩容的新部分赋值后再打印时,原数据也过来。


剖析

 不知道你是否会有疑问,为啥这里要赋值呢?

 第一种情况下:

  1. realloc 会找更大的一块可以存的下总大小的空间。
  2. 将原空间的数据拷贝过来。
  3. 释放原来开辟的空间。
  4. 返回新地址。
  • 而第二种情况则返回旧的地址。

动态内存的常见错误 

1.对空指针解引用

 执行此代码时就会报警告 “取消对 NULL 指针“p”的引用” 所以我们在动态开辟内存之前一定要判断一下是否开辟成功,所以我们会选择断言一下,或用 strerror(errno)来判断。


2.越界访问

 此时造成越界访问,编译时程序会崩掉。


3.对非动态开辟内存的释放

 此时的程序也是崩了,提一点数组名是首元素地址(常量),不可修改,而指针变量指向的地址属于变量,是可以修改的。


4.使用 free 释放动态内存的一部分

 这里开辟的空间首地址是p,而p++了一下,指向了下一个整型的地址,所以这就属于部分动态内存的释放,同样报错的,所以我们在使用动态内存空间时,最好不要改变首地址的指向。


5.对同一块动态内存的反复释放


但是如果你将动态开辟的地址置为空指针之后再次释放空指针此时就没问题


6.动态内存忘记释放(内存泄漏) 

当使用动态内存开辟空间时,使用完之后忘记释放的话或者程序不结束的话就会造成内存泄漏,也就是该内存空间被占用,即申请空间空间不使用,不能被其他进程获取,浪费该部分的空间,导致程序运行速度减慢甚至系统崩溃等严重后果


 

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CR0712

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值