C语言 — 动态内存管理

news2025/7/27 19:06:07

目录

  • 1.malloc和free函数
    • 1.1 malloc函数
    • 1.2 free函数
    • 1.3 malloc函数的使用
  • 2.calloc函数
    • 2.1 calloc函数
    • 2.2 calloc函数的使用
  • 3.realloc函数
    • 3.1 realloc函数
    • 3.2 realloc函数的使用
  • 4.动态内存管理笔试题
    • 4.1 笔试题(1)
    • 4.2 笔试题(2)
  • 5.柔性数组
    • 5.1 柔性数组定义
    • 5.2 柔性数组的使用

1.malloc和free函数

1.1 malloc函数

在这里插入图片描述
malloc函数的功能是向内存申请一块连续的内存空间,并将内容初始化为随机值,申请的大小是参数size,单位是字节,返回类型是void*类型的指针。

在这里插入图片描述
malloc函数的返回值:如果申请成功,会返回申请的内存空间起始位置的地址,如果申请失败会返回NULL(空指针).

1.2 free函数

在这里插入图片描述

free函数的功能是将开辟的内存空间释放,参数是开辟内存空间的起始地址,释放后参数ptr并不为NULL(空指针),因此使用free函数释放内存空间的同时,需要将ptr置为空指针;如果ptr本身为NULL,free函数不会执行。

1.3 malloc函数的使用

#include<stdio.h>
#include<stdlib.h>
//malloc函数的使用
int main()
{
	//开辟十个整型的空间大小
	//需要类型转换为int*类型的指针作为返回值
	int* ptr = (int*)malloc(10 * sizeof(int));

	//判断是否为NULL指针
	if (ptr == NULL)
	{
		//输出错误原因
		perror("malloc");
		return 1;//终止程序
	}

	//使用for循环初始化
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		ptr[i] = i + 1;
	}

	//输出打印
	for (i = 0; i < 10; i++)
	{
		printf("%d ", ptr[i]);
	}

	//释放内存空间
	free(ptr);
	ptr = NULL;//赋值为空指针
	return 0;
}

按F10启动调试观察malloc函数空间的开辟和释放的过程:观察开辟后内存空间的值
在这里插入图片描述
使用for循环初始化后的内容
在这里插入图片描述

输出初始化的内容1-10

在这里插入图片描述
按F10观察执行free函数后,开辟内存空间的内容,以及参数的变化

在这里插入图片描述

在使用free函数后需要及时将参数ptr置为空指针,否则会导致非法访问内存空间,导致程序奔溃。

在这里插入图片描述

2.calloc函数

2.1 calloc函数

在这里插入图片描述
calloc函数的功能与malloc一样,向内存申请一块连续的内存空间;与malloc函数不同的是,calloc函数有两个参数,第一个参数是元素个数,第二个参数是一个元素的大小,单位是字节,返回值是void*类型的指针。

在这里插入图片描述
如果开辟成功,返回开辟空间的起始地址,开辟失败,返回NULL(空指针)。

2.2 calloc函数的使用

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#pragma warning(disable:4996)//strcpy在VS中可能报警告,提示不安全,
//使用此指令可以不报警告,安全使用strcpy函数
//calloc的使用

struct Stu
{
	char name[20];//名字
	int age;//年龄
	float score[3];//成绩
};
int main()
{
	//开辟1个结构体大小
	//需要类型转换为struct Stu*类型的指针作为返回值
	struct Stu* ptr = (struct Stu*)malloc(1 * sizeof(struct Stu));
	                       //第一个参数元素个数,第二个元素一个元素大小

	//判断是否为NULL指针
	if (ptr == NULL)
	{
		//输出错误原因
		perror("calloc");
		return 1;//终止程序
	}

	float score1[3] = { 90.00f,85.50f,99.00f };
	//初始化
	strcpy((ptr->name,"Mary");//ptr->name表示name成员首元素地址
	ptr->age = 20;
	memcpy(ptr->score, score1,sizeof(score1));//ptr->score表示score成员首元素地址
	
	//输出打印
	printf(" name: %s\n age: %d\n score: %.2f  %.2f  %.2f",
		ptr->name, ptr->age, ptr->score[0], ptr->score[1], ptr->score[2]);

	//释放内存空间
	free(ptr);
	ptr = NULL;//赋值为空指针
	return 0;
}

按F10启动调试,观察calloc函数使用后内存空间的变化:使用calloc函数后,内存空间开辟成功,将内容初始化为随机值或者0。

在这里插入图片描述
初始化后
在这里插入图片描述

输出

在这里插入图片描述

free函数释放空间后,将参数置为空指针

在这里插入图片描述
在这里插入图片描述

3.realloc函数

3.1 realloc函数

在这里插入图片描述
realloc函数的功能是当开辟的内存空间不够或者多余时,进行内存空间的调整;第一个参数是调整空间的起始地址,第二个参数是调整后内存空间的大小,返回值是void*类型的指针。

在这里插入图片描述
在这里插入图片描述
如果开辟成功有两种情况,第一种是在原有的基础上,后面追加调整补充的空间,返回第一个参数的地址;第二种是重新开辟一块新的内存空间,将开辟的内存空间的起始地址返回;如果开辟失败返回空指针。

3.2 realloc函数的使用

#include<stdio.h>
#include<stdlib.h>
int main()
{
	//使用calloc开辟5个整型大小
	int* ptr = (int*)calloc(5, sizeof(int));
	
    //判断是否开辟失败
	if (ptr == NULL)
	{
		perror("calloc");//输出错误内容
		return 1;
	}

	//调整为6个整型大小
	int* ptr1 = (int*)realloc(ptr, 6 * sizeof(int));
	if (ptr1 == NULL)
	{
		//1.将原开辟的空间释放,并置空指针
		free(ptr);
		ptr = NULL;

		//2.输出错误信息
		perror("realloc");
		return 1;//终止程序
	}

	//释放内存空间,并置空指针
	free(ptr1);
	ptr1 = NULL;
	return 0;
}

按F10启动调试观察使用realloc函数后的内容变化:调用calloc函数后的内容

在这里插入图片描述

观察调用realloc函数后的内容

在这里插入图片描述
最后将空间释放,回收内存空间,最后不free(ptr)是因为,realloc函数在重新开辟新空间时,会将原有的参数开辟的空间释放,最后就不用再次释放,只需要释放调整后的内存空间。

在这里插入图片描述

4.动态内存管理笔试题

4.1 笔试题(1)

//以下程序的运行结果是什么?
#include <stdio.h>
#include <stdlib.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;
}

在这里插入图片描述


程序运行的结果是程序崩溃,因为GetMemory函数传参str,使用char*p接收,p变量是str的一份临时拷贝,
改变形参不能改变实参的值,所以在调用strcpy函数函数时,str是NULL,导致程序终止。

4.2 笔试题(2)

//以下程序的运行结果是什么?存在什么问题?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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;
}

程序可以正常输出hello,但是开辟内存空间后没有的释放内存空间,导致内存泄露。

在这里插入图片描述

5.柔性数组

5.1 柔性数组定义

柔性数组是存在于结构体中的最后一个成员,使用柔性数组的结构体必须至少包含两个成员,如下:

struct S
{
	int i;
	int arr[0];//柔性数组
};

sizeof计算时不会包含柔性数组的大小。

#include<stdio.h>
struct S
{
	int a;
	char ch[0];//柔性数组
};

int main()
{
	printf("%zu", sizeof(struct S));
	return 0;
}

在这里插入图片描述

5.2 柔性数组的使用

#include<stdlib.h>

struct Peo//人的结构体
{
	char name[20];//名字
	int age;//年龄
	char adress[20];//通讯地址
	char tele[12];//联系方式
	
};
struct Contact//通讯录
{
	int count;//当前存储信息数量
	int capacity;//当前容量
	struct Peo data[0];//柔性数组(结构体数组)
};
int main()
{
	//开辟空间:一个整型和十个struct Peo大小
	struct Contact* ptr = (struct Contact*)malloc(sizeof(int) + 10 * sizeof(struct Peo));

	//判断
	if (ptr == 0)
	{
		perror("malloc");
		return 1;
	}

	//使用
	//......
	//......

    //调整(内存空间不足时,根据count和capacity的值进行调整)
    //......
    //......

	//释放空间
	free(ptr);
	ptr = NULL;

	return 0;
}

柔性数组使用的好处:

1.灵活的内存管理‌:柔性数组允许结构体的最后一个成员是一个未知大小的数组。这意味着在动态分配内存时,可以根据实际需求来改变数组的长度,从而实现了内存的灵活管理‌。

2.提高访问速度‌:由于柔性数组直接作为结构体的一个成员,访问时不需要通过指针进行间接访问,这减少了访存次数,提高了访问速度‌。

‌3.减少内存碎片‌:通过动态分配内存,柔性数组可以更有效地利用内存空间,减少内存碎片的产生‌。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2398876.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《TCP/IP 详解 卷1:协议》第5章:Internet协议

IPv4和IPv6头部 IP是TCP/IP协议族中的核心协议。所有TCP、UDP、ICMP和IGMP 数据都通过IP数据报传输。IP提供了一种尽力而为、无连接的数据报交付服务。 IP头部字段 IPv4 头部通常为 20 字节&#xff08;无选项时&#xff09;&#xff0c;而 IPv6 头部固定为 40 字节。IPv6 不…

学习STC51单片机26(芯片为STC89C52RCRC)

每日一言 真正的强者&#xff0c;不是没有眼泪&#xff0c;而是含着泪依然奔跑。 硬件&#xff1a;4G模块 这个是接线原理&#xff0c;我们也只要知道这个4根线的连接就好了&#xff0c;我们也是连接到USB转TTL的模块上 要插卡哈......... 随后我们下载一个叫做亿佰特的调试助…

Nginx详解(三):ngx_http_rewrite_module模块核心指令详解

概要&#xff1a; 在 Nginx 的众多功能模块中&#xff0c;ngx_http_rewrite_module是实现请求动态处理的核心组件&#xff0c;它通过一系列指令实现 URI 重写、条件判断、响应返回等功能。本文将以 CentOS 7.9 环境为例&#xff08;主机名www.a.com&#xff0c;IP 172.25.0.10…

【笔记】在 MSYS2(MINGW64)中正确安装 Poetry 的指南

#工作记录 在 MSYS2&#xff08;MINGW64&#xff09;中正确安装 Poetry 的指南 一、背景说明 在 MSYS2&#xff08;MINGW64&#xff09;环境中&#xff0c;即使已经安装了 pip&#xff0c;也不建议直接使用 pip install poetry 来安装 Poetry。 这是因为 MSYS2 使用自己的包…

IDEA项目推送到远程仓库

打开IDEA——>VCS——>Creat Git 选择项目 push提交到本地 创建远程仓库 复制地址 定义远程仓库 推送 推送成功

【后端架构师的发展路线】

后端架构师的发展路线是从基础开发到技术领导的系统性进阶过程&#xff0c;需融合技术深度、架构思维和业务洞察力。以下是基于行业实践的职业发展路径和关键能力模型&#xff1a; 一、职业发展阶梯‌ 初级工程师&#xff08;1-3年&#xff09;‌ 核心能力‌&#xff1a;掌…

matlab/simulink TLC语法基础练习实例

一、基本语法测试方法 1.新建一个脚本&#xff0c;保存扩展名为tlc,本例中是tst.tlc&#xff0c;设置当前工作路径为保存的tlc文件路径&#xff0c;在tlc文件里面输入下面的代码&#xff0c;然后保存&#xff1a; %warning test 2.在MATLAB的命令窗口输入&#xff1a; tlc …

蓝桥杯国赛训练 day1

目录 k倍区间 舞狮 交换瓶子 k倍区间 取模后算组合数就行 import java.util.HashMap; import java.util.Map; import java.util.Scanner;public class Main {static Scanner sc new Scanner(System.in);public static void main(String[] args) {solve();}public static vo…

ESP32之Linux编译环境搭建流程

背景&#xff1a;为了解决 “windows环境中编译ESP32代码速度慢” 的问题&#xff0c;现搭建一个Linux环境&#xff0c;让windows下的VScode连接到Linux环境&#xff0c;VSCode负责编辑代码&#xff0c;虚拟机用于编译代码。 目录 一、安装VMware 1.1 获取VMware安装包 1.2…

UE5打包项目设置Project Settings(打包widows exe安装包)

UE5打包项目Project Settings Edit-Project Settings- Packaging-Ini Section Denylist-Advanced 1&#xff1a;打包 2&#xff1a;高级设置 3&#xff1a;勾选创建压缩包 4&#xff1a;添加要打包地图Map的数量 5&#xff1a;选择要打包的地图Maps 6&#xff1a;Project-Bui…

便捷高效能源服务触手可及,能耗监测系统赋能智能建筑与智慧城市

在建筑行业迈向智能化、精细化管理的进程中&#xff0c;传统建筑管理模式因信息割裂、数据利用不足等问题&#xff0c;逐渐难以满足现代建筑复杂的运营需求。楼宇自控系统实现了建筑设备的智能调控&#xff0c;BIM技术则构建了建筑的三维数字化模型&#xff0c;当两者相遇&…

ISO18436-2 CATII级振动分析师能力矩阵

ISO18436-2021是当前针对针对分析师的一个标准&#xff0c;它对振动分析师的能力和知识体系做了4级分类&#xff0c;这里给出的是一家公司响应ISO18436的CATII级标准&#xff0c;做的一个专题培训的教学大纲。摘自&#xff1a; 【振動噪音產學技術聯盟】04/19-23 ISO 18436-2…

dvwa4——File Inclusion

LOW: 先随便点开一个文件&#xff0c;可以观察到url栏变成这样&#xff0c;说明?page是dvwa当前关卡用来加载文件的参数 http://10.24.8.35/DVWA/vulnerabilities/fi/?pagefile1.php 我们查看源码 &#xff0c;没有什么过滤&#xff0c;直接尝试访问其他文件 在url栏的pag…

Spring Boot养老院管理系统源码分享

概述 基于Spring Boot开发的养老院管理系统&#xff0c;该系统通过智能化管理模块&#xff0c;为养老机构提供高效运营解决方案。 主要内容 后台管理功能 系统后台功能完善&#xff0c;左侧导航栏涵盖首页、安全巡查管理、设备管理等模块。设备管理界面以表格形式清晰展示设…

go|context源码解析

文章目录 Context接口Deadline()Done()Err()Value() canceler接口ctxemptyCtxcancelCtxtimerCtxvalueCtx 基本使用cancelCtxvalueCtx 首先看一下源码对“context”的描述&#xff0c; When a Context is canceled, all Contexts derived from it are also canceled. 当一个Cont…

如何在PowerBI中使用Analyze in Excel

如何在PowerBI中使用Analyze in Excel 之前分享过如何使用DAXStudio将PowerBI与Excel连接 &#xff0c;今天介绍另外一个工具&#xff0c;也可以实现同样的功能&#xff0c;Analyze in Excel。 使用Analyze in Excel 第一步&#xff1a; 首先准备好一个PBIX文件&#xff0c…

大模型分布式训练笔记(基于accelerate+deepspeed分布式训练解决方案)

文章目录 一、分布式训练基础与环境配置&#xff08;1&#xff09;分布式训练简介&#xff08;2&#xff09;如何进行分布式训练&#xff08;3&#xff09;分布式训练环境配置 二、数据并行-原理与实战&#xff08;pytorch框架的nn.DataParallel&#xff09;1&#xff09;data …

鸿蒙UI开发——组件的自适应拉伸

1、概 述 针对常见的开发场景&#xff0c;ArkUI开发框架提供了非常多的自适应布局能力&#xff0c;这些布局可以独立使用&#xff0c;也可多种布局叠加使用。本文针对ArkUI提供的拉伸能力做简单讨论。 拉伸能力是指容器组件尺寸发生变化时&#xff0c;增加或减小的空间全部分…

鸿蒙仓颉语言开发教程:自定义弹窗

假期第一天&#xff0c;祝大家端午节快乐。昨天观看了时代旗舰尊界S800的发布&#xff0c;不得不感慨这车真好啊&#xff5e; 放假闲来无事&#xff0c;继续跟大家分享仓颉语言的开发教程&#xff0c;今天介绍一下自定义弹窗。 仓颉语言中的自定义弹窗和ArkTs类似&#xff0c…

Python 数据分析与可视化实战:从数据清洗到图表呈现

目录 一、数据采集与初步探索 二、数据清洗的七种武器 1. 缺失值处理策略 2. 异常值检测与修正 3. 数据类型转换技巧 三、数据转换的魔法工坊 1. 透视表与交叉表 2. 窗口函数实战 3. 文本数据处理 四、可视化呈现的艺术 1. 基础图表进阶用法 2. 高级可视化方案 3.…