C语言动态内存空间分配

1. 前言

        在讲内存分配前,咱来聊一下为什么会有内存分配这个概念呢,大家都知道C语言当中是有着许多的数据类型,使用这些数据类型就会在内存上开辟其相对应的空间,那既然会开辟相应的空间,为什么还会有内存分配呢,我们会发现C语言分配内存空间,是已经被固定好了的,固定开辟多少空间,但是这样开辟空间会不会太死板了呢,如果我用不上这些空间呢,这样会导致内存的利用率很低,有没有一种,我需要多少空间,就开辟多少空间的方法呢,这个时候C语言就为我们引进了动态内存分配的这个概念,顾名思义,就是你想分配多少空间就分配多少空间,下边我们来一起了解一下怎样在内存上开辟我们想要的空间

(注意:使用这些函数都需要包含#include<stdlib.h>这个头文件)

2. malloc函数:

2.1 malloc函数的声明:

函数向内存申请⼀块连续可⽤的空间,并返回指向这块空间的指针(由于不知道你要申请的类型,使用返回值为void*)

  1. 如果开辟成功,则返回⼀个指向开辟好空间的指针。
  2. 如果开辟失败,则返回⼀个 NULL 指针,因此malloc的返回值⼀定要做检查
  3.  如果参数 size 为0,malloc的⾏为是标准是未定义的取决于编译器决于编译器(vs2022)

所以一个malloc的使用可以分为以下几步:

  1. 使用malloc函数对内存空间申请指定空间
  2. 判断返回值是否为NULL
  3. 内存空间的释放

2.2 malloc函数的简单应用:

#include <stdlib.h>
int main()
{
	int* p = (int*)malloc(sizeof(int) * 5); //向内存申请5个int型的内存空间
	if (p == NULL)  //判断返回值是否为空
	{
		perror("malloc");  //为空,则报错malloc函数处有问题
		return 1;
	}
	free(p);  //释放内存,在下边会说喔
    p = NULL;  //将p指针赋为NULL,防止出现野指针
	return 0;
}

3. free函数:

        在前边的代码当中,我们了解到free函数是专门用来释放动态申请的内存空间,同时也说明了它只能释放动态申请的内存空间,关于这一点兄弟们不要搞混咯

3.1 free函数声明:

​​​​​

  1. 如果参数 ptr 指向的空间不是动态开辟的,那free函数的⾏为是未定义的
  2. 如果参数 ptr 是NULL指针,则函数什么事都不做
关于free函数的使用前面有提到,有需要的兄弟可以往上翻翻

4. malloc与free的实际运用:

int main()
{
	int* p = (int*)malloc(sizeof(int) * 10);//申请10个int型元素
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	for (int i = 0; i < 10; i++)  //对malloc申请的空间进行赋值
	{
		*(p + i) = i;
	}
	for (int i = 0; i < 10; i++)  //输出
	{
		printf("%d ", *(p + i));
	}
	free(p);  //释放空间
	p = NULL;
	return 0;
}
//执行结果
0 1 2 3 4 5 6 7 8 9

5. calloc函数:

5.1 calloc函数的声明:

calloc

void* calloc (size_t num, size_t size);
  1. 与malloc相似,也是用来开辟内存空间
  2. 开辟num个size大小的元素
  3. 相较于malloc来说,calloc开辟好空间后,还会将空间内的每个字节初始化为0

5.2 calloc的简单应用:

下边我们来一段代码调试进行了解:

int main()
{
	int* p1 = (int*)calloc(10, sizeof(int));
	if (p1 == NULL)
	{
		perror("calloc");
		return 1;
	}
	free(p1);
	return 0;
}

题解分析:

6 realloc函数:

        当你觉得动态内存申请的空间,不够使用的时候,这个时候就可以运用realloc函数对内存空间进行扩容,所以realloc函数是对动态内存空间进行扩容的

6.1 realloc函数的声明:

realloc

void* realloc (void* ptr, size_t size);

        1. ptr 是要调整的内存地址

        2. size 为调整之后新大小
        3. 返回值为调整之后的内存起始位置
        4.  这个函数调整原内存空间⼤⼩的基础上,还会将原来内存中的数据移动到新的空间

6.2 relloc函数扩容内存时的两种情况:

        1. 原有的空间在扩容的时候,后边有足够的空间

        2.  原有的空间在扩容的时候,后边没有足够的空间

6.3 relloc函数的简单应用:

int main()
{
	int* p = (int*)malloc(sizeof(int) * 10);
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	for (int i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	printf("\n");
	int* p1 = (int*)realloc(p,sizeof(int) * 15);  //扩容5个int型
	if (p1 == NULL)
	{
		perror("realloc");
		return 2;
	}
	for (int i = 10; i < 15; i++)
	{
		*(p1 + i) = i;
	}
	for (int i = 0; i < 15; i++)
	{
		printf("%d ", *(p1 + i));
	}
	free(p1);
	p1 = NULL;
	return 0;
	return 0;
}
//执行结果
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14

6.4 柔性数组:

        在c99中规定,一个结构体中最后的数组如果没有指定大小,则这个数组被称为柔性数组

柔性数组的特点:

  1. 结构中的柔性数组成员前⾯必须⾄少⼀个其他成员
  2. sizeof 返回的这种结构⼤⼩不包括柔性数组的内存
  3. 包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小
举例:
struct S
{
	int a;
	char a1;
	int a3[];
}q;

int main()
{
	printf("%结构体大小为:zd", sizeof(q)); //计算结构体大小,了解柔性数组是否分配了大小
	struct S* s = (struct S*)malloc(sizeof(struct S) + sizeof(int) * 5); //为a3数组分配了5个int型的空间
    return 0;
}

题解分析:

6.4.1 柔性数组的简单应用:

        申请一块动态内存空间后,对齐扩容,扩大柔性数组的内存空间,然后对柔性数组进行赋值,最后输出结构体中成员的值:

//柔性数组
struct S
{
	int a;
	char a1;
	int a3[];
}q;
	int main()
	{
		int ret = sizeof(struct S);
		struct S* p2 = (struct S*)malloc(sizeof(struct S));
	
		if (p2 == NULL)
		{
			perror("malloc");
			return 1;
		}
		p2->a = 100;
		p2->a1 = 48;
	
		struct S* p3 = (struct S*)realloc(p2, sizeof(struct S)+sizeof(int)*5); //扩容柔性数组的大小
		printf("%zd\n", sizeof(p3));
		if (p3 == NULL)
		{
			perror("realloc");
			return 2;
		}
		p2 = NULL;
		for (int i = 0; i < 5; i++)
		{
			p3->a3[i] = i;
		}
	
		printf("%d\n", p3->a);
		printf("%d\n", p3->a1);
		for (int i = 0; i < 5; i++)
		{
			printf("%d ", p3->a3[i]);
	
		}
		free(p3);
		p3 = NULL;
		return 0;
	}
//执行结果
8
100
48
0 1 2 3 4

7. 常见的动态内存错误:

7.1 使用free对非动态内存进行释放:

int main()
{
	int a = 10;
	int* p = &a;
	free(p); //free对非动态内存申请的空间进行释放
	return 0;
}

执行结果:

7.2 动态内存越界访问:

int main()
{
	int* p = (int*)malloc(sizeof(int) * 5);//向内存动态申请5个int型空间
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	for (int i = 0; i < 6; i++) //向p执行的空间放入6个int型元素
	{
		*(p + i) = i;
	}
	return 0;
}

执行结果:

(程序死循环加上报错)

7.3 使⽤free释放⼀块动态开辟内存的⼀部分:

int main()
{
	int* p = (int*)malloc(sizeof(int) * 5);
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	for (int i = 0; i < 5; i++) 
	{
		*p = i;
		p++;   //每执行一次p++,则p指向的地址加1
	}
	free(p);
	return 0;
}

题解分析:

执行结果:

(程序死循环加上报错)

7.4 对同⼀块动态内存多次释放

int main()
{
	int* p = (int*)malloc(sizeof(int) * 5);
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	free(p);
	free(p);
	return 0;
}

执行结果:

(程序死循环加上报错)

7.5 动态开辟内存忘记释放(内存泄漏):

        什么意思呢,简单来讲,就是你申请了空间,但是没有及时的将空间释放掉,与上边多次释放刚好相反:

int main()
{
	int* p = (int*)malloc(sizeof(int) * 5);
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	//free(p);  //为注释掉的内容
	//free(p);
	return 0;
}

执行以后不会报错,但是会造成内存上的浪费


7.6 对NULL指针的解引⽤操作

int main()
{
	int* p = (int*)malloc(INT_MAX*10);
	*p = 100;
	free(p);
	return 0;
}

由于并没有判断p是否为NULL,当p为NULL时,就会发生以下报错:

(死循环直至程序崩溃)

(今日分享到此结束,如觉得对您有帮助,还请点赞关注支持一下,Thanks♪(・ω・)ノ!!!)

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

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

相关文章

【数据库】数据库的介绍、分类、作用和特点,AI人工智能数据如何存储

欢迎来到《小5讲堂》&#xff0c;大家好&#xff0c;我是全栈小5。 这是《数据库》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识…

深度学习理论基础(三)封装数据集及手写数字识别

目录 前期准备一、制作数据集1. excel表格数据2. 代码 二、手写数字识别1. 下载数据集2. 搭建模型3. 训练网络4. 测试网络5. 保存训练模型6. 导入已经训练好的模型文件7. 完整代码 前期准备 必须使用 3 个 PyTorch 内置的实用工具&#xff08;utils&#xff09;&#xff1a; ⚫…

蓝桥杯 - 穿越雷区

解题思路&#xff1a; dfs 方法一&#xff1a; import java.util.Scanner;public class Main {static char[][] a;static int[][] visited;static int[] dx { 0, 1, 0, -1 };static int[] dy { 1, 0, -1, 0 };static long min Long.MAX_VALUE;static long count 0;publi…

先进电气技术 —— (控制理论)何为稳定性?

一、系统稳定性 在控制理论中&#xff0c;系统稳定性是一个非常关键的概念&#xff0c;它主要涉及系统对外界扰动或内部变动的响应行为。以下是与系统稳定性相关的一些核心名词及其解释&#xff1a; 基本概念 稳定性&#xff08;Stability&#xff09; 系统稳定性是指当系统受…

Autosar工具链配置 CanNM

CAN网络管理filter 网管报文范围0x600~0x6FF repeat message time 超时时间 接收到主动唤醒源&#xff0c;网管报文快发周期&#xff0c;次数&#xff1b;正常周期发送时间 网管报文btye设置&#xff1a;1、重复消息请求位设置 2、ECU地址 wait bus-sleep 定时设置以及网管报…

蓝桥杯第十四届--子树的大小

题目描述 给定一棵包含 n 个结点的完全 m 叉树&#xff0c;结点按从根到叶、从左到右的顺序依次编号。 例如下图是一个拥有 11 个结点的完全 3 叉树。 你需要求出第 k 个结点对应的子树拥有的结点数量。 输入格式 输入包含多组询问。 输入的第一行包含一个整数 T &#xf…

telnet远程管理设备

实验目的&#xff1a;通过本机管理远端设备&#xff0c;模拟本地网卡和远端设备可以通信&#xff0c;配置telnet账户&#xff0c;远程管理设备&#xff0c;不用进入机房方式 拓扑图 云朵模拟本机的网卡&#xff0c;配置ar1的g0/0/0口IP后&#xff0c;确保在同一网络&#xff0…

【正点原子探索者STM32F4】TFTLCD实验学习记录

【正点原子探索者STM32】LCD实验学习记录 硬件硬件连接软件设计变量类型定义LCD参数结构体LCD地址结构体 函数定义读写命令和数据简介6个基本函数坐标设置函数画点函数读点函数字符显示函数LCD初始化 小结参考 硬件 STM32F407、4.3寸LCD屏 硬件连接 LCD_BL(背光控制)对应 PB1…

传输层 --- TCP (上篇)

目录 1. TCP 1.1. TCP协议段格式 1.2. TCP的两个问题 1.3. 如何理解可靠性 1.4. 理解确认应答机制 2. TCP 报头中字段的分析 2.1. 序号和确认序号 2.1.1. 序号和确认序号的初步认识 2.1.2. 如何正确理解序号和确认序号 2.2. TCP是如何做到全双工的 2.3. 16位窗口大小…

Redis Desktop Manager可视化工具

可视化工具 Redis https://www.alipan.com/s/uHSbg14XmsL 提取码: 38cl 点击链接保存&#xff0c;或者复制本段内容&#xff0c;打开「阿里云盘」APP &#xff0c;无需下载极速在线查看&#xff0c;视频原画倍速播放。 官网下载&#xff08;不推荐&#xff09;&#xff1a;http…

【智能优化算法】IHAOAVOA(一种改进的混合天鹰优化算法(AO)和非洲秃鹫优化算法(AVOA))

发表在Mathematical Biosciences and Engineering的文章&#xff1a;IHAOAVOA: An improved hybrid aquila optimizer and African vultures optimization algorithm for global optimization problems.https://www.x-mol.com/paperRedirect/1572654041256222720 01.引言 天鹰…

Linux 安装系统可视化监控工具 Netdata

目录 About 监控工具 NetdataLinux 系统安装 Netdata关于 openEuler1、查看内核信息2、查看主机信息3、查看 dnf 包管理器的版本 Netdata 安装1、更新系统环境相关 rpm 包2、查看 netdata 包信息3、安装 netdata 包4、编辑 netdata.conf 配置5、启动 netdata 服务6、查看 netda…

页面静态化:Freemarker入门案例和常用指令教程

页面静态化其实就是将原来的动态网页(例如通过ajax请求动态获取数据库中的数据并展示的网页)改为通过静态化技术生成的静态网页&#xff0c;这样用户在访问网页时&#xff0c;服务器直接给用户响应静态html页面&#xff0c;没有了动态查询数据库的过程。 那么这些静态HTML页面…

TestNG Include and exclude

在这篇文章中&#xff0c;我们将详细讨论TestNG的包含和排除标签。下面是我们将在这篇文章中看到的要点- 包含和排除包第二&#xff0c;包括和排除测试方法最后&#xff0c;包括和排除组 我们只能将exclude标记与packages、methods和run标记&#xff08;groups的子标记&#…

公园景区小红书抖音打造线上流量运营策划方案

【干货资料持续更新&#xff0c;以防走丢】 公园景区小红书抖音打造线上流量运营策划方案 部分资料预览 资料部分是网络整理&#xff0c;仅供学习参考。 共70页可编辑&#xff08;完整资料包含以下内容&#xff09; 目录 公园的线上运营方案&#xff1a; 一、运营目标 1. 品…

微电网优化:基于小龙虾优化算法COA的微电网优化(提供MATLAB代码)

一、微电网优化模型 微电网是一个相对独立的本地化电力单元&#xff0c;用户现场的分布式发电可以支持用电需求。为此&#xff0c;您的微电网将接入、监控、预测和控制您本地的分布式能源系统&#xff0c;同时强化供电系统的弹性&#xff0c;保障您的用电更经济。您可以在连接…

TCP三次握手过程及抓包分析

TCP三次握手过程 一、TCP分段格式二、TCP三次握手三、Wireshark抓包分析 一、TCP分段格式 二、TCP三次握手 三、Wireshark抓包分析

cmake中报错undefined reference to `pthread_create‘的解决方法

出现报错&#xff1a; 解决方法 一般网上会建议在终端指令g/gcc后面增加参数-pthread,但是我们没有用到g/gcc指令. cmake的解决方法是在CMakeLists.txt文件里面增加一行. add_executable(server2 main.cpp) target_link_libraries(server2 pthread)问题就解决了

[VulnHub靶机渗透] pWnOS 2.0

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

lora pingpang系统 4

1 深入了解LoRa技术原理 1.1 LoRa扩频通信原理 1.1.1 模拟无线通信&#xff1a; 模拟无线通信是一种使用模拟信号传输数据的通信方式。这种通信方式已经被数字无线通信所取代&#xff0c;因为数字通信具有更高的效率和可靠性。 天线&#xff1a;从空中接收到的无线电波转换成…