C语言学习系列->动态内存管理

news2024/12/19 22:48:26

在这里插入图片描述

文章目录

  • 前言
  • 概述
  • 🚩malloc and free
    • 🔜malloc
    • 🔜free
  • 🚩calloc and realloc
    • 🔜calloc
    • 🔜realloc

前言

要想学好数据结构,在C语言学习过程中就需要把指针、结构体和动态内存管理学好。在前面的文章,小编已总结了指针和结构体,本篇水文 小编为大家整理了一下C语言中的动态内存管理。

概述

已经掌握了开辟空间,为什么还要有动态内存分配?

int a=1;    //申请4个字节
char c='g';     //申请1个字节
int arr[30]={0};   //申请120个字节

请添加图片描述
这些申请好了之后,空间大小就是固定的,不能再去做调整,并不能满足实际生活需要。

long long ago 我们说过变长数组,变长数组的大小可以由变量来指定,但是一旦创建好之后,依然还是不能调整大小,而且只适用于C99中。

总的来说,申请的空间大小不能灵活调整。

因此,在C语言中:动态内存管理就给了程序员一个权限,自己申请,自己使用,使用完自己释放。

🚩malloc and free

🔜malloc

malloc是C语言中的动态内存开辟函数:

头文件:stdlib.h

malloc申请函数是在堆区上申请的

void* malloc (size_t size);

Allocates a block of size bytes of memory, returning a pointer to the
beginning of the block.

The content of the newly allocated block of memory is not initialized,
remaining with indeterminate values.

If size is zero, the return value depends on the particular library
implementation (it may or may not be a null pointer), but the returned
pointer shall not be dereferenced.

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

code

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

int main()
{
	//申请10个整型空间,即40个字节
	int *p = (int*)malloc(10 * sizeof(int));
	//开辟失败
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	//开辟成功,则使用空间
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;   //0 1 2 3 4 5 6 7 8 9 
	}
	//打印
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	return 0;
}

🔜free

开辟完内存后,在结束后需要释放

有两种释放方式:
1.free
2.程序结束后,操作系统自己释放

void free (void* ptr);

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

code

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

int main()
{
	//申请10个整型空间,即40个字节
	int *p = (int*)malloc(10 * sizeof(int));
	//开辟失败
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	//开辟成功,则使用空间
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;   //0 1 2 3 4 5 6 7 8 9 
	}
	//打印
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}

free( p ) 仅仅是把 p 指针指向的这块空间归还给了操作系统

free只能释放动态申请的空间

🚩calloc and realloc

🔜calloc

void* calloc (size_t num, size_t size);

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

code

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int *p = (int*)calloc(10, sizeof(int));
	if(NULL != p)
	{
		int i = 0;
		for(i=0; i<10; i++)
		{
			printf("%d ", *(p+i));
		}
	}
	free(p);
	p = NULL;
	return 0;
}

输出结果

0 0 0 0 0 0 0 0 0 0

如果我们对申请的内存空间的内容要求初始化,那么可以很⽅便的使⽤calloc函数来完成任务。

🔜realloc

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

• realloc函数的出现让动态内存管理更加灵活。
• 有时会我们发现过去申请的空间太⼩了,有时候我们⼜会觉得申请的空间过⼤了,那为了合理的时
候内存,我们⼀定会对内存的⼤⼩做灵活的调整。那 realloc 函数就可以做到对动态开辟内存⼤⼩的调整。

• ptr 是要调整的内存地址
• size 调整之后新⼤⼩
• 返回值为调整之后的内存起始位置
• 这个函数调整原内存空间⼤⼩的基础上,还会将原来内存中的数据移动到 新 的空间
• realloc在调整内存空间的是存在两种情况:
情况1:原有空间之后有⾜够⼤的空间
情况2:原有空间之后没有⾜够⼤的空间

在这里插入图片描述
情况1
当是情况1 的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发⽣变化。
情况2
当是情况2 的时候,原有空间之后没有⾜够多的空间时,扩展的⽅法是:在堆空间上另找⼀个合适⼤⼩的连续空间来使⽤。这样函数返回的是⼀个新的内存地址。

code

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int *ptr = (int*)malloc(100);
	if(ptr != NULL)
	{
		//业务处理
	}
	else
	{
		return 1;
	}
	//扩展容量
	//代码1 - 直接将realloc的返回值放到ptr中
	ptr = (int*)realloc(ptr, 1000);//这样可以吗?(如果申请失败会如何?)
	//代码2 - 先将realloc函数的返回值放在p中,不为NULL,在放ptr中
	int*p = NULL;
	p = realloc(ptr, 1000);
	if(p != NULL)
	{
		ptr = p;
	}
	//业务处理
	free(ptr);
	return 0;
}

在这里插入图片描述

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

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

相关文章

2006-2019年全国30省绿色创新效率、绿色投资效率:基于SBM-DEA测算面板数据(数据+Stata代码)

1、来源&#xff1a;各省年鉴、统计局、科技年鉴 2、时间&#xff1a;2006-2019 3、范围&#xff1a;全国 30 个省份 4、指标&#xff1a; 原始数据指标&#xff1a;R&D 全时人员当量 (万人年)、R&D 资本存量 (亿元&#xff1b;利用以 1999 年为初期永续存量法&a…

css之Flex弹性布局(父项常见属性)

文章目录 &#x1f415;前言&#xff1a;&#x1f3e8;定义flex容器 display:flex&#x1f3e8;在flex容器中子组件进行排列&#x1fa82;行排列 flex-direction: row&#x1fa82;将行排列进行翻转排列 flex-direction: row-reverse&#x1f3c5;按列排列 flex-direction: col…

postman自动化运行接口测试用例

做过接口测试的人&#xff0c;应该都知道postman &#xff0c;我们在日常的时候都可以利用postman做接口测试&#xff0c;我们可以把接口的case保存下来在collection里面&#xff0c;那么可能会有这样的需求&#xff0c;我们怎么把collection的用例放到jenkins中定时执行呢&…

C++STL的迭代器(iterator)

一、定义 迭代器是一种检查容器内元素并且遍历容器内元素的数据类型。 【引用自&#xff1a;C迭代器&#xff08;iterator&#xff09;_c iterator_NiUoW的博客-CSDN博客】迭代器是一个变量&#xff0c;相当于容器和操纵容器的算法之间的中介。C更趋向于使用迭代器而不是数组下…

【GESP】2023年06月图形化三级 -- 自幂数判断

文章目录 自幂数判断【题目描述】【输入描述】【输出描述】【参考答案】其他测试用例 自幂数判断 【题目描述】 自幂数是指N位数各位数字N次方之和是本身&#xff0c;如153是3位数&#xff0c;其每位数的3次方之和是153本身&#xff0c;因此153是自幂数&#xff0c;1634是4位数…

STM32进行LVGL裸机移植

本文的移植参考的是正点原子的课程《手把手教你学LVGL图形界面编程》 基于该课程和《LVGL开发指南_V1.3》“第二章 LVGL 无操作系统移植”&#xff0c;然后结合自身的实际情况进行整理。 先根据自己的习惯&#xff0c;创建基础的单片机工程&#xff0c;然后在APP业务层和DRIVE…

cdm解决‘ping‘ 或者nslookup不是内部或外部命令,也不是可运行的程序或批处理文件的问题

当我们在执行cmd时&#xff0c;会出现不是内部或外部命令&#xff0c;也不是可运行的程序的提示。 搜索环境变量 点开高级 >> 环境变量 打开Path&#xff0c;看是否在Path变量值中存在以下项目&#xff1a; %SystemRoot%/system32; %SystemRoot%; %SystemRoot%/Syste…

【JVM系列】- 探索·运行时数据区的私有结构

探索运行时数据区的私有结构 文章目录 探索运行时数据区的私有结构运行时数据区的结构与概念认识线程了解守护线程和普通线程JVM系统线程 程序计数器&#xff08;PC寄存器&#xff09;概述PC寄存器的特点PC寄存器的作用 透过案例了解寄存器为什么需要用PC寄存器来存放字节码的指…

C语言基础-循环与数组

目录 循环 while 循环&#xff1a; for 循环&#xff1a; do while 循环&#xff1a; 中断循环&#xff1a; break continue&#xff1a; 数组 数组&#xff1a;用来装一组数的类型。声明形式如下&#xff1a; 定义数组类型变量&#xff1a; 下标&#xff1a;即各元素…

初出茅庐的小李博客之ESP8266获取自己B站粉丝数据

获取方式 ESP8266发起HTTP请求解析json数据 获取粉丝API: https://api.bilibili.com/x/relation/stat?vmid349513188API浏览器测试返回结果 {"code": 0,"message": "0","ttl": 1,"data": {"mid": 349513188, …

Python+Appium实现自动化测试

一、环境准备 1.脚本语言&#xff1a;Python3.x IDE&#xff1a;安装Pycharm 2.安装Java JDK 、Android SDK 3.adb环境&#xff0c;path添加E:\Software\Android_SDK\platform-tools 4.安装Appium for windows&#xff0c;官网地址 Redirecting 点击下载按钮会到GitHub的…

【safetensor】介绍和基础代码

Hugging Face, EleutherAI, StabilityAI 用的多 介绍 文件形式 header&#xff0c;体现其特性。如果强行将pickle或者空软连接 打开&#xff0c;会出现报错。解决详见&#xff1a;debug 连接到其他教程结构和参数 安装 with pip:Copied pip install safetensors with con…

阶段六-Day05-MyBatis3

一、多表查询&#xff08;面试题&#xff09; 1. 介绍 多表查询是在企业中必不可少的&#xff0c;无论多么简单的项目里通常会出现多表查询的操作。因为只要是关系型数据库&#xff0c;在设计表时都需要按照范式进行设计&#xff0c;为了减少数据冗余&#xff0c;都会拆成多个…

String、StringBuffer、StringBuilder 适合的应用场景

文章目录 String适用场景示例代码 StringBuffer适用场景示例代码 StringBuilder适用场景示例代码 性能比较总结 &#x1f389;欢迎来到Java学习路线专栏~String、StringBuffer、StringBuilder 适合的应用场景 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff…

《视觉SLAM十四讲》公式推导(二)

CH3-5 四元数表示旋转 三维空间中任意点均可用一个纯虚四元数表示即 p [ 0 , v ] T \boldsymbol{p}[0,\boldsymbol{v}]^T p[0,v]T&#xff0c;经一个单位四元数 q \boldsymbol{q} q的旋转后&#xff0c;得到 p ′ \boldsymbol{p} p′&#xff0c;则 p ′ q p q − 1 (3-5-1)…

STM32F4_中英文显示

目录 1. 液晶显示逻辑 2. 汉字显示原理 3. 实验程序 3.1 main.c 3.2 text.c 3.3 text.h 3.4 fontupd.c 3.5 fontupd.h 1. 液晶显示逻辑 字符编码&#xff1a; 由于计算机只能识别 0 和 1&#xff0c;文字也只能以 0 和 1 的形式在计算机里存储&#xff0c;所以我们需要…

算法通过村第十六关-滑动窗口|青铜笔记|滑动很简单

文章目录 前言滑动窗口的基本思想入门题目练习子数组最大平均数最长连续递增序列 总结 前言 提示&#xff1a;我宁愿做自己&#xff0c;做卑微的自己&#xff0c;也不愿做别人&#xff0c;无论那会多么快乐。 --《美丽新世界》 我们在数组和链表的部分就已经接触到了双指针的思…

IMX6ULL开发——第一个驱动程序

实现第一个应用程序&#xff1a;在IMX6ULL开发板上运行驱动程序hello_drv_test hello_drv_test #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <string.h>/** ./hel…

生产者消费者模式(c++实现)

生产者消费者模式思路就是&#xff1a;一批专门生产资源的线程 和一批专门处理资源的线程以及一个线程安全的任务队列组成的 。并且当任务队列满的时候阻塞生产线程&#xff0c;任务队列为空的时候阻塞消费线程。 要实现一个生产者消费者队列 1。需要实现线程同步&#xff0c;…

react的setState做了什么

1、为什么需要setState setState的作用是帮助我们更改数据的同时并且通知视图进行渲染。因为React并不会绑定视图和state&#xff0c;需要我们手动去更新视图。 2、setState什么时候是同步的&#xff0c;什么时候是异步的 setState这个方法在调用的时候是同步的&#xff0c;…