IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> C语言进阶~动态内存管理!!! -> 正文阅读

[数据结构与算法]C语言进阶~动态内存管理!!!

为什么会存在动态内存管理呢?

我们经常使用的是:

#include<stdio.h>
int main(){
int i = 0;
char arr[10] = { 0 };
return 0;
}

1.这两种情况是在栈上开辟的
2.数组在声明之前必须指定长度,他所需的的内存在编译的时候分配
2。有时候我们在使用数组之前不知道,要用多大的空间,以上这种方法就不能满足了

在这里插入图片描述

动态内存函数的介绍

malloc和free介绍

在这里插入图片描述
这个函数是向内存申请一块连续的内存空间并且返回这块空间起始的指针
1.如果开辟成功了,返回这块空间的起始指针
2.如果开辟失败,返回NULL指针
3. 返回值是void
,参数是size_t ,意思是你在形参哪里输入你要开辟多少字节的空间
*

在这里插入图片描述1.free函数用来释放动态开辟的内存。
如果中放的指针指向的空间不是动态开辟的,那free函数的行为是未定义的。如果是NULL指针,则函数什么事都不做

malloc和free都声明头文件<stdlib.h>
看如何引用的

int main(){
	int num = 0;
	scanf("%d", &num);
	int* p = malloc(num*sizeof(int));
	int i = 0;
	if (p != NULL){//判断开辟成功了吗
		for (i = 0; i < num; i++){
			*(p + i) = 8;//malloc不会自动赋值的  要自己赋值,他只管开辟空间
		}
	}
	for (i = 0; i < num; i++){
		printf("%d  ", p[i]);//打印  *(p+i)~p[i]
	}
	free(p);//这释放完可不可以不把p指针指向NULL呢
	p = NULL;
	return 0;
}

在这里插入图片描述

malloc开辟之后没有赋值的情况
在这里插入图片描述

calloc介绍

在这里插入图片描述
1 第一个参数:你要开辟的空间个数,第二个参数:是开辟空间的大小
2 与malloc的区别是这个开辟空间每个字节都置为0

引用:

int main(){//开辟10个int的空间
	int *p = calloc(10, sizeof(int));
	if (p != NULL){
		int i = 0;
		for (i = 0; i < 10; i++){
			printf("%d ",*(p + i));//打印
		}
	}
	free(p);
	p = NULL;
	return 0;
}

realloc介绍

在这里插入图片描述realloc大白话说就是可以改变你开辟的内存空间的大小,有了这个函数是的,开辟内存,和内存使用就很灵活了
第一个参数是你要改变空间的地址,第二个是要改成多大的,返回的地址是你改完后的空间的首地址,这个分成两种情况

在这里插入图片描述看一下情况

int main(){
	int*p = calloc(10, sizeof(char));//开辟了10个连续的10个char类型的空间
	p = realloc(p, 20);
	//直接用p来接收行吗?

	return 0;
}

在这里插入图片描述
解决:

int main(){
	int*p = calloc(10, sizeof(int));
	int*ptr = realloc(p, 80);
	if (ptr != NULL){
		p=ptr;//如果ptr返回来的不是空指针说明开辟成功,再把它他赋給p指针
		// 如果是空指针就不会把空指针赋給p,避免赔了夫人又折兵
	}
	int i= 0;
	for (i = 0; i < 20; i++){
		printf("%d ", p[i]);
	}
	free(p);
	p = NULL;
	return 0;
}

常见的几种动态内存错误

1,对NULL指针的解引用操作。

int main(){
	int *p = (int*)malloc(1000);
	int i = 0;//这里没判断是不是空指针
	for (i = 0; i < 10; i++){
		*(p + i) = i;//如果p是空指针就是错误了
	}
	
	return 0;
}

2,动态空间的越界访问

int main(){
	int *p = (int*)malloc(10 * sizeof(int));//创建了10个整形的内存空间,40字节
	if (p != NULL){
		int i = 0;//你之创建了10个空间,但循环赋值40次,这就越界访问了
		for (i = 0; i < 40; i++){
			*(p + i) = i;
		}
	}
	free(p);
	p = NULL;
	return 0;
}

3,对非动态内存free释放

在这里插入图片描述

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

在这里插入图片描述

int main(){
	int *p = (int*)malloc(10 * sizeof(int));
	if (p != NULL){
		int i = 0;
		for (i = 0; i < 5; i++){
			*p++ = i;
		}
	}
	free(p);
	p = NULL;
	return 0;
}

5,动态内存倍多次释放

在这里插入图片描述

6,动态内存忘记释放

在这里插入图片描述

1 动态内存可以用free释放
2 程序结束

几道经典的笔试题

第一道:

#include<stdio.h>
#include<string.h>
void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, “hello world”);
printf(str);
}
int main(){
Test();
return 0;
}

在这里插入图片描述

第二道有女朋友的都会做:

char *GetMemory(void)
{
char p[] = “hello world”;
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
int main(){
Test();
return 0;
}

在这里插入图片描述

第三道:

void Test(void)
{
char *str = (char *)malloc(100);
strcpy(str, “hello”);
free(str);
if (str != NULL)
{
strcpy(str, “world”);
printf(str);
}
}
int main(){
Test();
return 0;
}

在这里插入图片描述

第四道:

void GetMemory(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, “hello”);
printf(str);
}
int main(){
Test();
return 0;
}

在这里插入图片描述
总结:
1.局部变量和函数形参实在栈上开辟的,出了作用域就会自动还给操作系统
2.而动态内存开辟,在堆上开辟的,需要手动销毁,或者程序结束自动销毁

柔性数组

柔性数组不咋常见,结构中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。
**特点:
结构中的柔性数组成员前面必须至少一个其他成员。
sizeof 返回的这种结构大小不包括柔性数组的内存。
在这里插入图片描述

包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小

在这里插入图片描述
int arr[];就是柔性数组成员,也可以是int arr[0]; 这样写
我们看看是如何使用的:

typedef struct str{
	int a;
	int arr[];
}pf;
int main(){
	//printf("%d", sizeof(pf));
	//sizeof(pf) 计算的是结构体的大小,柔性数组我们设定为10个整形的空间吧
	pf *p = (pf*)malloc(sizeof(pf)+10 * sizeof(int));
	p->a = 10;
	int i = 0;
	for (i = 0; i < p->a; i++)
	{
		p->arr[i] = i;
		printf("%d ", p->arr[i]);

	}
	return 0;
}

在这里插入图片描述
看到这是不是感觉,有没有柔性数组都行呀,不就是为int a 和 int arr[]动态开辟空间吗,分开辟不久完了吗,其实不然,看代码

typedef struct str{
	int a;
	int *arr;
}pf;
int main(){
	pf *ps = (pf*)malloc(sizeof(pf));
	if (ps == NULL){
		return 1;
	}
	ps->arr = (pf*)malloc(10 * sizeof(int));
	int i = 0;
	//应用
	for (i = 0; i < 10; i++){
		ps->arr[i] = i;//已经给arr指针开辟可10个空间,现在我们循环赋值
	}
	free(ps->arr);
	ps->arr = NULL;
	free(ps);
	ps = NULL;
	return 0;
}

在这里插入图片描述
在这里插入图片描述
这是相当于开辟了两次呀;由于你是开辟了两次,你就得释放两次呀
在这里插入图片描述
为啥分先后呢,你先把ps释放了,就找不到arr指针指向的那块空间了
柔性数组的好处:方便内存释放,释放一次就OK

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-09-29 10:33:19  更:2021-09-29 10:33:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 13:51:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码