C语言——动态内存

 

 大家好!我是保护小周,本期为大家带来超详细的C语言——动态内存管理,论动态内存在C++/C中的重要性,学好动态内存约等于看穿了C语言~确定不来看看嘛~

 


目录

一、为什么存在动态内存分配

(1)创建一个变量

(2)创建一个数组

二、动态内存函数介绍

2.1 malloc()和free()

2.2 calloc()

2.3 realloc()

三、常见的动态内存错误

3.1 对NULL指针的解引用操作

3.2 对动态内存的越界访问

3.3 对非动态内存的free()释放

3.4 使用free()释放一块动态开辟内存的一部分

3.5 对同一块动态开辟的空间多次释放

3.6 对动态开辟的空间忘记释放

四、经典笔试题

4.1 请问以下程序有那些错误

4.2 请问运行Test()函数会有什么结果

4.3 请问运行Test()函数会有什么结果

4.4 请问运行Test()函数会有什么结果

C/C++ 程序内存分配的几个区域:

五、柔性数组

快来跟我一起学习吧!


一、为什么存在动态内存分配

当前我们知道的内存的使用方式:

(1)创建一个变量

创建一个变量就一定会开辟空间,例如:int  sum=0;  如果sum变量在函数内部创建的,这个时候它是局部变量,又或者你定义的的sum全局变量,无论是全局变量还是局部变量,作为整型的sum变量都会向内存申请4个字节的空间,无非就是局部变量是在内存的栈区上申请的全局变量是在内存的静态区上申请的

(2)创建一个数组

创建一个局部范围的数组,是在栈区上申请的,同样如果创建的是一个全局范围的数组,也是静态区上申请的

我们来画个图换一种思维理解:

 两种方式:一种是一次申请一个变量的空间,另一种是一次申请一片连续的空间。

上述两种开辟空间的方式有两个特点:

1.空间开辟的大小是固定的。

2.数组在申明的时候,必须指定数组的长度,所需内存在编译时分配。

那么是不是有了这两种常见的使用内存的方式就够了?

举个例子:我们采用一个结构体描述学生信息,学号、姓名、性别、年龄等信息;然后我们需要定义一个结构体类型变量,或者结构体类型数组来存储信息,如果我们采用一个数组存储一个班级的学生信息,我们当然可以根据一个班级里的人数来定义数组的大小,这时候如果班级有的同学转走了,我们把他的信息处理掉之后,表面上是删除了,实际上属于他原来的空间一直存在,是不是造成了一定程度上空间的浪费,又或者是增加了一些新的同学,数组的大小是固定的,满了之后我们又该如何处理,增加这些新同学的信息呢?有的人这样想,我们把数组的大小定义的大一些,一点点的空间浪费可以接受的,那么如果我采用这个结构体类型的数组存放全校同学的信息,这个误差就非常大了。

#include<stdio.h>

//学生学习成绩类型定义
struct grade
{
	int Chinese;//语文
	int math;   //数学
	int English;//英语
};
//学生信息类型定义
struct student //定义一个student的结构体类型
{
	char number[12];//学号
	char name[12];  //姓名
	char sex[5];    //性别
	int age;        //年龄
	char tele[12];  //电话
	char addr[20];  //地址
	struct grade report;//成绩单
};

int main()
{
	//定义一个student类型的数组data;
	struct student  data[50];//data可以存放50个同学的信息
	//如果实际录入信息为30,就造成空间上的浪费
	//如果实际需录入信息60,那我们data的空间不够
	
	return 0;
}

如果大家在结构体方面有什么不明白的可以观看博主的另一篇博客:结构体(初阶)

写文章-CSDN博客https://mp.csdn.net/mp_blog/creation/editor/123829425

使用数组的方式有他的局限性,应该怎么办?动态内存分配,等空间满了之后自动的在堆区上开辟我们理想大小的空间,用来存储。如果我们删除某个同学的信息之后,可以执行释放掉用于存储被删除同学信息的空间,这样是不是非常方便?


二、动态内存函数介绍

动态内存函数的在头文件<stdlib.h>

2.1 malloc()和free()

C语言提供了一个动态内存开辟的函数:

void* malloc (size_t size);

这个函数可以向内存申请一块连续可用的空间,并返回指向这块从堆区上开辟的空间的指针。

(1)如果空间开辟成功,则返回一个指向开辟好空间起始位置的指针

(2)如果空间开辟失败,则返回一个值为NULL的指针,我们可以利用这一点来判断malloc()是否成功开辟空间

(3)返回值的类型是void *,所以malloc()函数不知道开辟空间的类型,类型需要我们自己来决定

这个时候我们就需要根据自己的需要进行强类型转换。

C语言提供了一个free()函数,专门是用来做动态内存的释放和回收的。

free()函数调用形式如下:

void free(void*ptr);

free()函数用来释放动态开辟的空间。

(1)如果参数 ptr 指向的空间不是动态开辟的,free()函数的行为是未定义的

(2)如果参数 ptr 是NULL指针,则函数什么事也不做

我们举一个简单的例子来看看怎么使用malloc()函数和free()函数;

#include<stdio.h>
#include<stdlib.h>

int main()
{
	//定义一个指针
	int* p=NULL;
	//指针p指向malloc()函数返回的空间的起始位置
	p=(int*)malloc(10*sizeof(int));//向内存的栈区申请10个整型的空间
	if (p==NULL)//判断申请空间是否成功
	{
		//打印错误提示
		perror("malloc");
		return;//中止程序
	}
	else//正常使用空间
	{
		int i = 0;
		for (i=0;i<10;i++)//给申请的空间赋值
		{
			*(p + i) = i;
		}
		//打印数据
		for (i=0;i<10;i++)
		{
			printf("%d ",*(p+i));
		}
	}
	//当动态申请的空间不再使用
	// 就应该还给操作系统
	//释放空间
	free(p);  //如果我们不释放不
评论 36
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

保护小周ღ

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

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

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

打赏作者

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

抵扣说明:

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

余额充值