C笔记(20)-动态内存管理

目录

一、动态内存分配存在的原因

二、四个相关函数

2.1 malloc 和 free

2.1.1 malloc

2.1.2 free

2.2 calloc 和 realloc

2.2.1 calloc

2.2.2 realloc

三、常见动态内存错误

3.1 对NULL指针的解引用操作

3.2 对动态开辟空间的越界访问

3.3 对非动态开辟内存使用free释放

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

3.5 对同一块动态内存多次释放

3.6 动态开辟内存忘记释放(内存泄露)

四、动态内存经典试题分析

4.1 题目1

4.2 题目2

4.3 题目3

4.4 题目4

五、柔性数组

5.1 柔性数组的特点

5.2 柔性数组的使用

5.3 柔性数组的优势

六、C/C++中程序内存区域划分总结


一、动态内存分配存在的原因

已经知道的内存开辟方式:

int val = 20;//在栈空间上开辟四个字节
char arr[10] = {0};//在栈空间上开辟10个字节的连续空间

这样的开辟方式存在以下特点:

  • 空间开辟⼤⼩是固定的。

  • 数组在申明的时候,必须指定数组的⻓度,数组空间⼀旦确定了⼤⼩不能调整 

二、四个相关函数

C语⾔引⼊了动态内存开辟,让程序员⾃⼰可以申请和释放空间。

2.1 malloc 和 free

2.1.1 malloc

//C语⾔提供了⼀个动态内存开辟的函数:
void* malloc(size_t size);

这个函数向内存申请⼀块连续可⽤的空间,并返回指向这块空间的指针。
• 如果开辟成功,则返回⼀个指向开辟好空间的指针。
• 如果开辟失败,则返回⼀个 NULL 指针,因此malloc的返回值⼀定要做检查。
• 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使⽤的时候使⽤者⾃⼰来决定。
• 如果参数 size 为0,malloc的⾏为是标准是未定义的,取决于编译器

2.1.2 free

//C语⾔提供函数free,专⻔是⽤来做动态内存的释放和回收的
//函数原型如下:
void free(void* ptr);

free函数⽤来释放动态开辟的内存。
• 如果参数 ptr 指向的空间不是动态开辟的,那free函数的⾏为是未定义的。
• 如果参数 ptr 是NULL指针,则函数什么事都不做。
malloc和free都声明在 stdlib.h 头⽂件中 。

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

int main()
{
	int* p = (int*)malloc(40);  
	//确定为整型后,强制转换,用整型指针接收。其他类型类似
	if (p == NULL)
	{
		perror("malloc");
		return 1; //异常返回
	}
	//使用空间
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i + 1;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}

    //释放
    free(p); //从开始开辟的地址开始释放内存,这里p变成野指针
    p = NULL;

    //如果不释放内存,程序又不结束的话,那部分内存空间将一直被占用

	return 0;
}

2.2 calloc 和 realloc

2.2.1 calloc

//C语⾔提供⼀个函数叫calloc,calloc函数也⽤来动态内存分配。
//原型如下:
void* calloc(size_t num, size_t size);

• 函数的功能是为 num 个⼤⼩为 size 的元素开辟⼀块空间,并且把空间的每个字节初始化为0
• 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0

#include<stdlib.h>

int main()
{
	//int * p = (int*)malloc(10 * sizeof(int));
	int* p = (int*)calloc(10, sizeof(int));
	if (p == NULL)
	{
		perror("calloc");
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}

	//释放
	free(p);
	p = NULL;

	return 0;
}

2.2.2 realloc

有时会我们发现过去申请的空间太⼩了或者太大了,为了合理的使⽤内存,会对内存的⼤⼩做灵活的调整。realloc 函数就可以做到对动态开辟内存⼤⼩的调整。

//函数原型如下:
void* realloc(void* ptr, size_t size);

• ptr 是要调整的内存地址
• size 是调整之后的新⼤⼩
• 返回值为调整之后的内存起始位置。
• 这个函数调整原内存空间⼤⼩的基础上,还会将原来内存中的数据移动到新的空间。
• realloc在调整内存空间的是存在两种情况:
        情况1:原有空间之后有⾜够⼤的空间,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发⽣变化。
        情况2:原有空间之后没有⾜够⼤的空间,扩展的⽅法是:在堆空间上另找⼀个合适⼤⼩的连续空间来使⽤。这样函数返回的是⼀个新的内存地址。

int main()
{
	int * p = (int*)malloc(20);
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}

	//使用
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		*(p + i) = i + 1;
	}
	//1 2 3 4 5
	
	//扩大空间
	int* ptr = (int*)realloc(p, 40);
	if (ptr != NULL)
	{
		p = ptr;
	}
	else
	{
		perror("realloc");
		return 1;
	}
	for (i = 5; i < 10; i++)
	{
		*(p + i) = i + 1;
	}
	for (i = 0; i < 10; i++)
	{
		
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值