C语言---动态内存管理

C语言—动态内存管理

文章目录

  • C语言---动态内存管理
  • 1. 为什么要进行动态内存分配
    • 1.1 动态内存管理所在的区域
  • 2. 动态内存函数的介绍
    • 2.1 malloc
      • 2.1.1 malloc语法
      • 2.1.2 malloc具体实例
    • 2.2 free
      • 2.2.1 free语法
      • 2.2.2 free具体实例
    • 2.3 calloc
      • 2.3.1 calloc语法
      • 2.3.2 calloc具体实例
    • 2.4 realloc
      • 2.4.1 realloc语法
      • 2.4.2 realloc调整空间时存在的情况
      • 2.4.3 realloc具体实例
  • 总结


1. 为什么要进行动态内存分配

我们已经掌握的内存开辟方式有:

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

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

  1. 空间开辟大小是固定的。
  2. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。

但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道,
那数组的编译时开辟空间的方式就不能满足了。这时候就只能试试动态存开辟了

1.1 动态内存管理所在的区域

在这里插入图片描述

2. 动态内存函数的介绍

2.1 malloc

2.1.1 malloc语法

void* malloc (size_t size);

这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。

  • 如果开辟成功,则返回一个指向开辟好空间的指针。
  • 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查
  • 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己
    来决定。
  • 如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。

2.1.2 malloc具体实例

代码如下(示例):

#include<errno.h>
#include<string.h>
#include<stdlib.h>

int main()
{
	//申请40个字节,用来存放10个整型
	int* p = (int*)malloc(40);
	//malloc函数语法格式上返回类型是void* ,但原因是因为开发者为使用者留存的一个可以自己改变的类型的方式
	//所以当使用malloc函数的时候,要清楚自己存放的类型是什么。同样要记住进行强制类型转换
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//存放1--10
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i + 1;
	}
	//打印
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	return 0;
}

2.2 free

2.2.1 free语法

void free (void* ptr);

free函数用来释放动态开辟的内存。

  • 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
  • 如果参数 ptr 是NULL指针,则函数什么事都不做。

2.2.2 free具体实例

首先在上述malloc代码中存在一个隐患,就是在向内存空间申请40个字节的时候,如果代码结束运行之后操作系统会回收40个字节的空间,但是如果代码一直在运行,并且申请的40字节的内存已经用完不想在使用的时候,就会造成内存浪费,这个时候就需要free函数去释放申请的内存空间。

代码如下(示例):

#include<errno.h>
#include<string.h>
#include<stdlib.h>

int main()
{
	//申请40个字节,用来存放10个整型
	int* p = (int*)malloc(40);
	//malloc函数语法格式上返回类型是void* ,但原因是因为开发者为使用者留存的一个可以自己改变的类型的方式
	//所以当使用malloc函数的时候,要清楚自己存放的类型是什么。同样要记住进行强制类型转换
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//存放1--10
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i + 1;
	}
	//打印
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	//free是释放申请的内存
	free(p);
	p = NULL;//主动将释放后的p指针赋值NULL,防止非法访问
	return 0;
}

2.3 calloc

2.3.1 calloc语法

void* calloc (size_t num, size_t size);
  • 函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。
  • 函数 malloc 申请到的空间没有初始化,直接返回起始地址, calloc 会在返回地址之前把申请的空间的每个字节初始化为全0

在这里插入图片描述

2.3.2 calloc具体实例

#include<errno.h>
#include<string.h>
#include<stdlib.h>

int main()
{
	int* pi = (int*)malloc(40);
	int* p = (int*)calloc(10, sizeof(int));
	if (NULL == p)
	{
		perror("calloc");
		return 1;
	}
	if (pi == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d\n", *(pi + i));
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	//释放
	free(p);
	free(pi);
	p = NULL;
	pi = NULL;
	return 0;
}

2.4 realloc

2.4.1 realloc语法

有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整。

void* realloc (void* ptr, size_t size);
  • ptr 是要调整的内存地址
  • size 调整之后新大小
  • 返回值为调整之后的内存起始位置
  • 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。

2.4.2 realloc调整空间时存在的情况

  • 情况1:原有空间之后有足够大的空间
  • 情况2:原有空间之后没有足够大的空间
    在这里插入图片描述
  • 当是情况1 的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。
  • 当是情况2的时候,realloc函数会找一个满足空间大小的新的连续空间,把旧的空间的数据,拷贝新空间的前面的位置,并且把旧的空间释放,同时返回新的空间地址
  • realloc如果扩容失败,就返回空指针

2.4.3 realloc具体实例

#include<errno.h>
#include<string.h>
#include<stdlib.h>

int main()
{
	int* pi = (int*)malloc(5*sizeof(int));
	if (NULL == pi)
	{
		perror("malloc");
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		*(pi + i) = 1;
	}
	//不够了,再增加5个整型
	int* ptr = realloc(pi, 10 * sizeof(int));//需要用新的指针来接收,防止扩容失败把旧的数据弄丢
	if (ptr != NULL)
	{
		pi = ptr;
	}
	//继续使用空间
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(pi+ i));
	}
	//释放空间
	free(pi);
	pi = NULL;
	return 0;
}

在这里插入图片描述


总结

  1. 在使用动态内存函数的时候要记得判断指针是都为NULL,否则容易出现问题。
  2. 在动态内存开辟之后,要及时使用free函数将其释放。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

42. 接雨水

题目介绍 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,1,0,1,3…

OpenShift 4 - 可观测性之用 OpenTelemetry+Jaeger 实现 Distributed Tracing

《OpenShift / RHEL / DevSecOps 汇总目录》 说明&#xff1a;本文已经在支持 OpenShift 4.13 的环境中验证 文章目录 技术架构部署 Distributed Tracing 运行环境安装测试应用并进行观测跟踪参考 说明&#xff1a; 本文使用的测试应用采用的是 “手动 Instrumentation” 方式在…

Linux系列---【CentOS 7通过MSTSC连接远程桌面】

安装对应的yum源 yum list lightdm xorgxrdp xrdp 可以看到这些软件都在epel中&#xff0c;如果没有的话&#xff0c;请先安装对应的yum源。命令如下&#xff1a; yum install -y epel-release 确认yum源没有问题之后&#xff0c;我们就可以进行安装了。 安装lightdm xorgxrdp…

【C语言】嵌入式C语言项目管理利器:深入理解Makefile的应用与实践

目录 一、makedile的概述 1、案例引入 2、makefile 3、Makefile优点 二、makefile的语法规则 1、语法规则 2、简单实战 三、makefile的变量 1、自定义变量 2、系统环境变量 3、预定义变量 4、高级makefile 一、makedile的概述 1、案例引入 gcc a.c b.c c.c ‐o …

EasyExcel写出包含多个sheet页的Excel

EasyExcel导出包含多个sheet页的Excel 1.引入依赖 引入如下的EasyExcel的依赖&#xff0c;或直接下载jar包 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.1</version></depende…

RT-Thread快速入门-定时器管理

1时钟节拍 任何操作系统都需要提供一个时钟节拍&#xff0c;以供系统处理所有和时间有关的事件&#xff0c;如延时、线程的时间片轮转调度以及定时器超时等。时钟节拍&#xff08;OS Tick&#xff09;是操作系统中最小的时间单位。 时钟节拍是特定的周期性中断&#xff0c;这…

Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 搜索、分页与结果过滤

文章目录 ⛄引言一、酒店搜索和分页⛅需求分析⚡源码编写 二、酒店结果过滤⌚需求分析⏰修改搜索业务 ✅效果图⛵小结 ⛄引言 本文参考黑马 分布式Elastic search Elasticsearch是一款非常强大的开源搜索引擎&#xff0c;具备非常多强大功能&#xff0c;可以帮助我们从海量数据…

【java实习评审】对热门小说更新时的聚集访问流量进行性能优化优化,有较好的设计

大家好&#xff0c;本篇文章分享一下【校招VIP】免费商业项目“推推”第一期书籍详情模块java同学的文档周最佳作品。该同学来自西安建筑科技大学软件工程专业。 本项目亮点难点&#xff1a;1 热门书籍在更新点的访问压力&#xff0c;2 书籍更新通知的及时性和有效性&#xff…

浅谈能源管理系统在水泥行业中设计分析

安科瑞 华楠 摘要&#xff1a;水泥企业作为我国产业结构中重要的耗能产业&#xff0c;同时对环境的污染也比较大&#xff0c;因此在水泥企业中建立能源管理系统&#xff0c;对水泥企业的生产过程过程进行全过程的监控和管理&#xff0c;对于降低企业的能源消耗和提高企业的经济…

24 鼠标常用事件

鼠标进入&#xff1a;enterEvent鼠标离开&#xff1a;leaveEvent鼠标按下&#xff1a;mousePressEvent鼠标释放&#xff1a;mouseRelaseEvent鼠标移动&#xff1a;mouseMoveEvent 提升为自定义控件MyLabel 代码&#xff1a; //mylabel.h #ifndef MYLABEL_H #define MYLABEL_H#…

ESP32(MicroPython) 两轮差速五自由度机械臂小车

这次的项目在软件上没多少调整&#xff0c;但本人希望分享一下硬件上的经验。 小车使用两轮差速底盘&#xff0c;驱动轮在小车中间&#xff0c;前后都要万向轮。这种形式可以实现0转弯半径&#xff0c;但受万向轮及用于加高的铜柱的规格限制&#xff0c;两个万向轮难以调到相同…

基于netlify生成custom SSL certificate

&#xff08;1&#xff09;腾讯云申请 &#xff08;2&#xff09;域名控制台解析 &#xff08;3&#xff09;Nginx下载&#xff08;crt: CA certificate Chain)

C++教程 从0开始

0基础C教程 从0开始 课堂现在开始 如需学习 请订阅该标签 什么是C&#xff1f; 这个不是太重要 自行查看该链接即可 C_百度百科C&#xff08;c plus plus&#xff09;是一种计算机高级程序设计语言&#xff0c;由C语言扩展升级而产生&#xff0c;最早于1979年由本贾尼斯特劳…

轻量级Firefox Send替代方案Gokapi

想不到一个域名的变动会影响这么大&#xff0c;访问量出现断崖式下跌。由此可见&#xff0c;平时的访问应该只是一些 RSS 的访问而已。 上面是 Pageviews&#xff0c;下面是 Uniques 今天略有回升 难怪那些大公司要花钱买域名了&#xff0c;不过老苏是个佛系的人&#xff0c;一…

使用MQ发送对象错误

说明&#xff1a;使用RabbitMQ发送消息&#xff0c;消息是对象&#xff0c;出现下面这样的错误&#xff1b; 错误信息&#xff1a;Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of com.hmall.item.pojo.Item (no Cr…

通过问题解决者手册推动你的结果 - 提高思维能力的 17 种方法

大部分人对产品管理的理解都是解决问题&#xff0c;这是他们的主要工作——找出客户的问题是什么并解决它们。但现在&#xff0c;热衷于解决问题的问题是&#xff0c;当我们看到问题时&#xff0c;本能反应是“我该如何解决它&#xff1f;” 这意味着&#xff1a;当我试图自己解…

SPEC CPU 2006 docker gcc:4 静态编译版本 Ubuntu 22.04 LTS 测试报错Invalid Run

runspec.sh #!/bin/bash source shrc ulimit -s unlimited runspec -c gcc41.cfg -T all -n 1 int fp > runspec.log 2>&1 & tail -f runspec.log runspec.log 由于指定了-T all&#xff0c;导致-n 1 失效&#xff0c;用例运行了三次&#xff08;后续验证&…

iptables的备份和还原

iptables的备份和还原 1、写在命令行当中的都是临时设置 2、把规则配置写在服务的文件当中&#xff0c;形成永久有效 备份&#xff1a;把iptables里面所有的配置都保存在/opt/ky30.bak中 iptables-save > /opt/ky30.bak 例&#xff1a; 默认配置文件在/etc/sysconfig/ip…

自然语言处理NLP介绍——NLP简介

目录 内容先进性说明内容大纲概要云服务器的使用 内容先进性说明 内容大纲概要 云服务器的使用

STM32MP157驱动开发——GPIO 和 和 Pinctrl 子系统的概念

文章目录 Pinctrl 子系统重要概念概述重要概念pin controller&#xff1a;client device&#xff1a; 代码中怎么引用 pinctrl GPIO 子系统重要概念概述在设备树中指定引脚在驱动代码中调用 GPIO 子系统头文件常用函数实例&#xff1a; BSP工程师针对芯片的寄存器写Pinctrl子系…