【C语言】动态内存管理

news2024/9/27 12:11:49

我们之前开辟的空间,大小固定,且在申明数组的时候,必须指定数组的长度。但是有时候我们需要的空间大小在程序运行的时候才知道,这就得动态内存开辟出马了。


目录

1.malloc和free

2.calloc

3.realloc

4.常见动态内存错误

5.经典笔试题

//两种动态内存传参 

//非法访问(返回栈空间问题)

6.C/C++程序的内存开辟 

7.柔性数组


1.malloc和free

头文件:#include<stdlib.h>

格式:void* malloc ( size_t size ) 

           size为申请的字节大小;

功能:向内存申请一块连续可用的空间,并返回指向这块空间的指针。

没有初始化,不赋初值时默认为随机值

如果开辟成功,则返回一个指向开辟好空间的指针;
如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查;

开辟空间过大时,也会开辟失败,Not enough space。 

申请到的空间没有初始化,直接返回起始地址。

头文件:#include<stdlib.h>

格式:void free (void* ptr);

功能:释放动态开辟的空间。

如果参数ptr指向的空间不是动态开辟的,那么free的行为是未定义的;

如果参数ptr是NULL指针,那么free函数什么都不做。

#include<errno.h>
#include<string.h>
#include<stdlib.h>
int main()
{
	//申请40个字节,用来存放10个整型
	int* p = (int*)malloc(40);
	//开辟失败,用strerror报错
	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;
		//打印
		printf("%d ", *(p + i));
	}
	//用free来释放申请的空间
	free(p);
	p = NULL;//手动将p置为空指针
	return 0;
}

2.calloc

头文件:#include<stdlib.h>

格式:void* calloc (size_t num, size_t size);

           num是开辟的元素个数,size是每个元素的大小;

功能:申请空间后会把空间初始化为0,然后返回起始地址。

开辟内存成功或失败同malloc。

#include<errno.h>
#include<string.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)calloc(10, sizeof(int));
	//开辟失败
	if (p == NULL )
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//开辟成功
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	free(p);
	p = NULL;
	return 0;
}

3.realloc

头文件:#include<stdlib.h>

格式:void* realloc (void* ptr, size_t size);

功能:对动态开辟的内存进行调整。

情况1:后面有足够的空间可以扩容,直接在后面续上新的空间,返回旧空间的起始地址;

情况2:后面没有足够的空间可以扩容,找一个满足空间大小的新的连续空间,把旧的空间里的数据拷贝到新的空间,并且把旧的空间释放,返回新空间的地址;

情况3:开辟失败,返回NULL。

若传的是空指针NULL,则相当于malloc。

#include<errno.h>
#include<string.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(5 * sizeof(int));
	if (NULL == p)
	{
		perror("malloc");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		*(p + i) = 1;
	}
	//不够,要增加5个整型的空间
	int* ptr = (int*)realloc(p, 5 * sizeof(int));
	if (ptr != NULL)//开辟成功
	{
		p = ptr;
        ptr = NULL;//更安全
	}
	//继续使用空间
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	//释放空间
	free(p);
	p = NULL;
	return 0;
}

4.常见动态内存错误

1> 对NULL指针的解引用操作:返回值一定要检查

2> 对动态开辟内存的越界访问:没开辟的内存不能访问

3> 对非动态开辟内存使用free释放:free只能释放动态开辟内存

4> 使用free释放一块动态开辟内存的一部分:释放的p指针必须指向起始地址

5> 对同一块内存多次释放:避免重复释放或在每次释放后牢记将p指针置为NULL

6> 动态开辟内存忘记释放(内存泄漏):free与内存函数一定要成对使用

5.经典笔试题

这几个题目原题(出处:《高质量的C/C++编程》)是给出错误的代码让我们改错,这里有的就直接放上正确的代码了哈~

//两种动态内存传参 

char* GetMemory1()//传值,返回地址
{
	char* p = (char*)malloc(100);
	return p;
}
void test1()
{
	char* str = NULL;
	str = GetMemory1();
	strcpy(str, "hello world!");
	printf(str);//哦吼吼还可以这样用
	free(str);//一定不能忘!
	str = NULL;
}
void GetMemory2(char** p)//传地址
{
	*p = (char*)malloc(100);
}
void test2()
{
	char* str = NULL;
	GetMemory2(&str);
	strcpy(str,"hello world!");
	printf(str);
	free(str);//一定不能忘!
	str = NULL;
}

int main()
{
	test1();
	test2();
	return 0;
}

//非法访问(返回栈空间问题)

char* GetMemory()
{
	char p[] = "hello world!";
	return p;
}
void test()
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}
int main()
{
	test();
	return 0;
}

上述代码存在问题,打印结果是一堆乱码(随机值)。

解释:进入GetMemory函数后,内存为p数组开辟了一段空间存放hello world, 并返回首元素地址p,但是在出GetMemory函数后该内存就被还给了操作系统,该数组就被销毁了,此时再利用str访问p指向的空间就会形成非法访问,打印乱码。

将 char p[] 改为 char* p 或在前面加上 static 即可成功打印。

6.C/C++程序的内存开辟 

7.柔性数组

定义:在C99标准下,结构体中的最后一个元素允许是未知大小的数组,这就是『柔性数组』成员。

特点:1> 结构中的柔性数组成员前面至少有一个其他成员;

2> sizeof 返回的这种结构体大小不包括柔性数组的内存;
3> 包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<errno.h>

struct S
{
	int n;
	char arr[];//或arr[0]
	          //表示数组大小未知,不是大小无限大
};
int main()
{
	printf("%d\n", sizeof(struct S));//4
	//创建空间
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 10 * sizeof(char));//多开辟空间适应柔性数组大小
	ps->n = 100;
	int i = 0;
	//赋值
	for (i = 0; i < 10; i++)
	{
		ps->arr[i] = 'c';
	}
	//打印
	for (i = 0; i < 10; i++)
	{
		printf("%c", ps->arr[i]);//cccccccccc
	}
	//增容
	struct S* ptr = (struct S*)realloc(ps, sizeof(struct S) + 20 * sizeof(char));
	if (ptr != NULL)
	{
		ps = ptr;
	}
	else
	{
		perror("realloc");
		return 1;
	}
	//使用
	printf("%d\n", sizeof(struct S));//还是4
	//释放
	free(ps);
	ps = NULL;
	return 0;
}

结束!!明天考C啦,Best wishes to me ! 

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

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

相关文章

TCP 握手过程 三次 四次

蛋老师视频 SYN 同步 ACK 确认 FIN 结束 核心机制是确定哪些请求或响应需要丢弃 SYN、ACK、FIN 通过 1/0 设置开启/关闭 开启SYN后&#xff0c;报文中会随机生成 Sequence序号 用于校验 &#xff08;应用可能发起多个会话&#xff0c;可以区分&#xff09; 服务器的同步序…

2023版D盾防火墙v2.1.7.2,主动防御保护,以内外保护的方式 防止网站和服务器给入侵。限制了常见的入侵方法,让服务器更安全

v2.1.7.2 (20230107) 2023-1-7 1.修正PHP一处文件检测的bug。 2.修正某些情况下无法文件加白问题。 v2.1.7.2 2022-10-13 1.针对aspx的样本加入了新的识别。 2.针对上传 doc格式文件提示“上传格式不符” 的修正。 3.工具“HTTPS安全”,把 TLS 1.1 和 TLS 1.0 设置为默认不选中…

杰理AD16N简介

一、概述&#xff1a; AD16N是杰理新出的一个MP3解码芯片&#xff0c;是高集成度的 32 位通用音频 SOC&#xff0c; 集成 40KByte SRAM&#xff0c; 时钟源可选内部 RC 或外部12MHz 晶振&#xff0c; 最高主频可达 160MHz&#xff1b; 主要是替代AC109N系列和AC608N、AC104N系列…

Python爬虫书写时遇到的问题汇总

文章目录python的xpath插件需要的库下载出现问题懒加载python 爬取图片,网址都正确但是下不下来的原因:爬取下来的文字包含Windows不能识别的特殊字符selenium的find_element_by_id()出现的问题爬虫信息写入mysql时的1045号错误python的xpath插件需要的库下载出现问题 ERROR: C…

MySQL特殊语法insert into ... on duplicate key update ...

一、前言 在日常开发中&#xff0c;经常会遇到这样的需求&#xff1a;查看某条记录是否存在&#xff0c;不存在的话创建一条新记录&#xff0c;存在的话更新某些字段。 比如下列伪代码&#xff1a; $row mysql_query($result);if($row){mysql_execute(update ...);}else{my…

MongoDB复习

目录 1.docker安装 2.mondo概念解析 3.数据库操作 4.基本数据类型 5. 适合使用场景 6.对集合操作 7.常用操作 1.docker安装 docker pull mongo:latest docker run -d --restartalways -p 27017:27017 --name mymongo -v /data/db:/data/db -d mongo docker exec -it m…

【SpringBoot高级篇】SpringBoot集成Sharding-JDBC分库分表

【SpringBoot高级篇】SpringBoot集成Sharding-JDBC分库分表Apache ShardingSphere分库分表分库分表的方式垂直切分垂直分表垂直分库水平切分水平分库水平分表分库分表带来的问题分库分表中间件Sharding-JDBCsharding-jdbc实现水平分表sharding-jdbc实现水平分库sharding-jdbc实…

数据结构-考研难点代码突破(查找算法 - 散列表(哈希表)C++实现除留余数法拉链法哈希)

文章目录1. 哈希表与解决哈希冲突的方法2. C实现除留余数法拉链法哈希1. 哈希表与解决哈希冲突的方法 散列表(Hash Table)&#xff0c;又称哈希表。是一种数据结构。 特点&#xff1a;数据元素的关键字与其存储地址直接相关。 关键字通过散列函数&#xff08;哈希函数&#…

Vue3.0文档整理:2、创建单页面应用程序

2.1&#xff1a;创建步骤 2.1.1&#xff1a;vue-cli 安装并执行create-vue:npm init vuelatest 它是Vue官方的项目脚手架工具 选择项目功能 除了第一项的项目名字外&#xff0c;其他可以暂时默认回撤或者选择No 切换到项目目录:cd <your-project-name> 安装项目依赖&…

山寨APP频出?安全工程师和黑灰产在较量

在山寨这个领域&#xff0c;没有人比黑灰产更懂模仿。 据安全从业者介绍&#xff0c;一般而言&#xff0c;对于成熟的山寨开发者来说&#xff0c;几天时间内就可以做出一套前端框架。服务器、源代码、域名、服务商这些内容的创建&#xff0c;通过网上租赁的方式就可以解决。 比…

【面试题】2023前端vue面试题及答案

Vue3.0 为什么要用 proxy&#xff1f;在 Vue2 中&#xff0c; 0bject.defineProperty 会改变原始数据&#xff0c;而 Proxy 是创建对象的虚拟表示&#xff0c;并提供 set 、get 和 deleteProperty 等处理器&#xff0c;这些处理器可在访问或修改原始对象上的属性时进行拦截&…

Window问题详解(下)

建议先看一下 Window问题详解(上) 思路② 既然会超时,那该怎么办呢? 显然需要一个更快速的方法来解决这个问题! 我们先来观察一下图片: 我们发现,每一次选中的数都会增加下一个。 !!!!! 因此,我们可以根据此特性优化时间!! 第一次先求出前 k − 1 k-1 k−

hdfs file system shell的简单使用

文章目录1、背景2、hdfs file system shell命令有哪些3、确定shell操作的是哪个文件系统4、本地准备如下文件5、hdfs file system shell5.1 mkdir创建目录5.2 put上传文件5.3 ls查看目录或文件5.4 cat 查看文件内容5.5 head 查看文件前1000字节内容5.6 tail 查看文件后1000字节…

Kubernetes12:k8s集群安全机制 ***与证书生成***

Kubernetes12&#xff1a;k8s集群安全机制 1、概述 1&#xff09;访问一个k8s集群的时候&#xff0c;需要经过以下三个步骤才能完成具体操作 第一步&#xff1a;认证操作第二部&#xff1a;鉴权操作&#xff08;授权&#xff09;第三部&#xff1a;准入控制操作 2&#xff…

小白晋升大牛的13个项目

入门到放弃 “C/C真的太难学了,我准备放弃了!” 很多初学者在学完C和C的基本语法后&#xff0c;就停滞不前了&#xff0c;最终走向“从入门到放弃”。其实&#xff0c;我们初学者最需要的不是HelloWorld&#xff0c;也不是语法知识的堆砌&#xff0c;需要的只是实战项目的磨砺…

「TCG 规范解读」基础设施架构和协议 (1)

可信计算组织&#xff08;Ttrusted Computing Group,TCG&#xff09;是一个非盈利的工业标准组织&#xff0c;它的宗旨是加强在相异计算机平台上的计算环境的安全性。TCG于2003年春成立&#xff0c;并采纳了由可信计算平台联盟&#xff08;the Trusted Computing Platform Alli…

9、STM32 SDIO FATFS(SD卡)

本篇文章使用STM32对SD卡通过SDIO配置&#xff0c;读写文件 在使用FATFS时值得注意得是若通信SDIO不启动DMA方式读写&#xff0c;容易导致其他任务中断打断读写时序&#xff0c;导致FATFS的执行出现异常&#xff0c;常见返回为FR_DISK_ERR, / (1) A hard error occurred in the…

【论文阅读】Robust Invertible Image Steganography (CVPR 2022)

作者来自北大深研院 网上已有介绍&#xff1a;https://news.pkusz.edu.cn/info/1002/6538.htm 针对传统图像隐写方法对高斯噪声、泊松噪声和有损压缩鲁棒性差的问题&#xff0c;提出了一种基于流的鲁棒可逆图像隐写框架RIIS。框架如下图 一、方法概述&#xff1a; 基于流的可…

计算机组成原理4小时速成6:输入输出系统,io设备与cpu的链接方式,控制方式,io设备,io接口,并行串行总线

计算机组成原理4小时速成6&#xff1a;输入输出系统&#xff0c;io设备与cpu的链接方式&#xff0c;控制方式&#xff0c;io设备&#xff0c;io接口&#xff0c;并行串行总线 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c…

计算机网络--网络层 IPv4地址概述(day05)

网络层 网络层提供的两种服务 IPv4地址概述 IPv4地址就是给因特网(Internet)上的每一台主机(或路由器&#xff09;的每一个接口分配一个在全世界范围内是唯一的32比特的标识符 IPv4地址的编址方法经历了如下三个历史阶段&#xff1a; 分类编址 1981划分子网 1985无分类编址…