第21讲:动态内存管理

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

2.malloc和free

3.calloc

4.realloc

5.笔试题

6.总结c/c++中程序内存区域划分

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

为了调整申请的空间大小,使程序员可以申请和释放空间,提高程序的灵活性

2.malloc和free

作用:分配一块连续可用的空间

头文件:stdlib.h

参数:类型是size_t,size是预分配大小(单位是字节)

返回值:类型是void*,若开辟失败,返回NULL;若开辟成功,返回这块空间(malloc开辟的空间)的首指针。

用法:开辟空间后,我们要保留这块空间的首指针,但malloc的返回值类型是void*,保留时要注意强制类型转换。最后,当开辟的空间不再用时,要用free函数释放空间,否则该空间将被一直占用,直到程序结束时才会被操作系统收回。

作用:释放动态开辟的内存。

头文件:stdlib.h

参数:类型是void*,参数是需解除分配的内存块;参数可以是NULL,此时函数什么也不做

返回值:无

上述代码看似没有问题,但却有个大问题。

如果malloc开辟空间失败呢?

返回NULL,而且我们还对NULL解引用了,这是非常可怕的,所以,修改如下:

这样才合适。

还有一个问题,释放pa指向的空间后,pa和p就是野指针了,要置NULL才合适

3.calloc

作用:开辟num个size字节的空间,并将每个开辟的字节初始化为0

头文件:stdlib.h

参数:类型都是size_t,num是开辟的元素个数,size是为每个元素分配的大小

返回值:和malloc一致

特点:与malloc区别不大,但malloc是不会对开辟空间初始化的,但calloc会。

4.realloc

作用:调整动态开辟的空间大小

头文件:stdlib.h

参数1:类型是void*,参数1是需调整的动态开辟的空间

参数2:类型是size_t,参数2是调整后的空间大小

参数1可以是NULL,此时将开辟一块size字节的空间,并返回首指针

返回值:类型是void*,若开辟失败,返回NULL;若开辟成功,返回调整后空间的首指针

注意:开辟后的空间未必是在原来的位置!所以要保留realloc的返回值才比较合适

#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
int main()
{
	int* p = (int*)malloc(16);//开辟空间,保留首指针
	if (p == NULL)
	{
		exit(-1);
	}
	int* pa = p;
	p = (int*)realloc(pa, 32);
	if (p == NULL)
	{
		exit(-1);
	}
	pa = p;
	free(pa);//回收空间
	pa = NULL;//防野指针
	p = NULL;
	return 0;
}

5.笔试题

题目1

#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void getmemory(char* p)
{
	p = (char*)malloc(100);
}
void test()
{
	char* str = NULL;
	getmemory(str);
	strcpy(str, "helo world");
	printf(str);
}
int main()
{
	test();
	return 0;
}

其实吧,并不会打印hello world,str是空指针,将指针变量传给getmemory不会改变指针变量,形参只是实参的一份临时拷贝,改变形参不会改变实参。

应将指针变量的地址传上去,然后解引用才能改变指针变量str

#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void getmemory(char** p)
{
	*p = (char*)malloc(100);
}
void test()
{
	char* str = NULL;
	getmemory(&str);
	strcpy(str, "helo world");
	printf(str);
}
int main()
{
	test();
	return 0;
}

这样就没问题了

题目2

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char* getmemory()
{
	 char p[] = "hello world";
	return p;
}
void test()
{
	char* str = NULL;
	str = getmemory();
	printf(str);
}
int main()
{
	test();
	return 0;
}

看起来没什么问题,因为字符串常量是存储在代码段的,不是栈区,即使出了函数也不会销毁,char p【】等价于char* p, 而p是指向字符串常量的指针,出函数后,p就被销毁了,但是变量p里面装的指针(也就是字符串常量的首指针)被返回了,应该是可以打印的。

但是吧,有个误区(上面红字是错的),我们忽略了字符数组初始化的特殊性,本代码的实质是将字符串拷贝一份,放到字符数组中,而这个字符数组是在栈区的,p是字符数组的首指针。出了函数,p指向的空间就被回收了,所以不能打印。

但是,我们只要稍稍修改:

#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char* getmemory()
{
	 const char* p = "hello world";
	return (char*)p;
}
void test()
{
	char* str = NULL;
	str = getmemory();
	printf(str);
}
int main()
{
	test();
	return 0;
}

这个代码是可以打印的,因为p不再是数组名了,字符数组的特殊初始化没有了,p就是字符串常量的首指针!

题目3

#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void getmemory(char** p,int num)
{
	*p = (char*)malloc(num);
}
void test()
{
	char* str = NULL;
	getmemory(&str, 100);
	strcpy(str, "hello");
	printf(str);
}
int main()
{
	test();
	return 0;
}

这个呀,没什么问题,是对的。因为我们取出str的地址,可以通过解引用的方式改变str。另外,在函数里用malloc申请内存,也是在堆区申请,函数结束对堆区的空间不影响。

6.总结c/c++中程序内存区域划分

堆区:动态开辟内存是在堆区上开辟的

栈区:声明变量,调用函数是在栈区申请内存

代码段:可执行代码,只读常量(例如字符串常量)

数据段(静态区):全局变量,静态变量储存在静态区

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

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

相关文章

安装Pytorch中的torchtext之CUDA版的正确方式

安装Pytorch和torchtext&#xff1a; Previous PyTorch Versions | PyTorch Installing previous versions of PyTorchhttps://pytorch.org/get-started/previous-versions/ 上面的命令如下&#xff1a; pip install torch2.1.2 torchvision0.16.2 torchaudio2.1.2 --index-…

单片机学习笔记---串口通信(2)

目录 串口内部结构 串口相关寄存器 串口控制寄存器SCON SM0和SM1 SM2 REN TB8和RB8 TI和RI 电源控制寄存器PCON SMOD 串口工作方式 方式0 方式0输出&#xff1a; 方式0输入 方式1 方式1输出。 方式1输入 方式2和方式3 方式2和方式3输出&#xff1a; 方式2和…

Nacos(2)

Nacos部署 服务器端docker部署&#xff08;需要服务器安装好docker&#xff09; 导入sql文件到服务器编写nacos配置文件custom.env&#xff08;示例如下&#xff0c;改为自己服务器nacos相关信息&#xff09; PREFER_HOST_MODEhostname MODEstandalone SPRING_DATASOURCE_PL…

CentOS7如何安装宝塔面板并实现固定公网地址远程访问

文章目录 一、使用官网一键安装命令安装宝塔二、简单配置宝塔&#xff0c;内网穿透三、使用固定公网地址访问宝塔 宝塔面板作为建站运维工具&#xff0c;适合新手&#xff0c;简单好用。当我们在家里/公司搭建了宝塔&#xff0c;没有公网IP&#xff0c;但是想要在外也可以访问内…

代码随想录算法训练营第12天—二叉树01 | ● 理论基础 ● *递归遍历 ● *迭代遍历

理论基础 文章讲解&#xff1a;https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html 二叉树是一种数据结构&#xff0c;常用于递归场景二叉树&#xff1a;binary tree&#xff0c;每个节点最多有两个子节点&#xff08;分支&a…

获取旁站 / C 段:第三方网站(附链接)

一、介绍 1.1 旁段 在网络安全的上下文中&#xff0c;"旁段"&#xff08;Pivot&#xff09;是指攻击者通过入侵一个网络中的一台计算机&#xff0c;然后利用该计算机作为跳板&#xff08;或者称之为“旁道”&#xff09;来访问其他计算机或网络资源的行为。 攻击者…

伦敦金交易平台:了解交易背后的世界

伦敦金交易平台是全球金融市场中备受关注的重要平台之一。作为国际金融中心&#xff0c;伦敦汇聚了众多金融机构和投资者&#xff0c;其金交所成为全球最大的现货黄金市场。在这个繁荣蓬勃的市场中&#xff0c;交易活跃&#xff0c;投资机会多样&#xff0c;吸引了众多投资者前…

DDoS攻击激增,分享高效可靠的DDoS防御方案

当下DDoS攻击规模不断突破上限&#xff0c;形成了 "网络威胁格局中令人不安的趋势"。专业数据显示&#xff0c;对比2022年上半年与2023年上半年&#xff0c;所有行业的DDoS攻击频率增加了314%。其中零售、电信和媒体公司遭受的攻击规模最大&#xff0c;三个垂直行业的…

手把手教你激活FL Studio 21.2.2.3914中文破解版2024年图文激活教程以及如何设置中文language

FL Studio 21.2.2.3914软件简介 fl studio 21.2.2.3914中文破解版作为一款极具创意性的音乐软件工作站软件&#xff0c;FL Studio已经成为了许多音乐制作人和音乐爱好者的首选。最新的FL Studio 21.2.2.3914中文破解版的发布&#xff0c;无疑将会引起更多人的关注。 ​ FL St…

NC6X单点登录设计文档说明

前言 因为业务场景需要&#xff0c;第三方系统有些工作需要经常到NC系统里做&#xff0c;如果每次去NC系统做业务单据&#xff0c;都需要反复登录&#xff0c;导致客户使用体验不是很好&#xff0c;所以需要开发实现从第三方系统单点登录到NC系统&#xff0c;提高客户满意度。 …

多维时序 | Matlab实现CNN-RVM卷积神经网络结合相关向量机多变量时间序列预测

多维时序 | Matlab实现CNN-RVM卷积神经网络结合相关向量机多变量时间序列预测 目录 多维时序 | Matlab实现CNN-RVM卷积神经网络结合相关向量机多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现CNN-RVM卷积神经网络结合相关向量机多变量时间序…

快准狠!在3D Slicer中,使用TotalSegmentator扩展可在1分钟内自动分割全身117个器官

本系列涵盖从 3D Slicer 医学图像查看器的基础使用到高级自动分割扩展程序的内容(从入门到高阶!),具体包括软件安装、基础使用教程,自动分割扩展(totalsegmentator, monai label)快速标注数据。 Tina姐:强烈建议做图像分割的宝宝们好好学习,跟着Tina姐涨姿势!本教程…

开关电源学习之Boost电路

如果我们需要给一个输入电压为5V的芯片供电&#xff0c;而我们只有一个3.3V的电源&#xff0c;那怎么办&#xff1f; 我们能不能把3.3V的电压升到5V&#xff1f; 一、电感的简介 而在升压的电路设计方案中&#xff0c;使用到一个重要的元器件&#xff1a;电感。 电感的特性…

44、WEB攻防——通用漏洞RCE代码执行多层面检测利用

文章目录 RCE分类&#xff1a; REC代码执行&#xff1a;引用脚本代码解析执行。例如&#xff0c;eval(phpinfo();)以php脚本解析phpinfo();。RCE命令执行&#xff1a;脚本调用操作系统命令。例如&#xff0c;system(ver)&#xff0c;命令执行能执行系统命令。 RCE漏洞对象&am…

C#中实现串口通讯和网口通讯(使用SerialPort和Socket类)

仅作自己学习使用 1 准备部份 串口通讯需要两个调试软件commix和Virtual Serial Port Driver&#xff0c;分别用于监视串口和创造虚拟串口。网口通讯需要一个网口调试助手&#xff0c;网络上有很多资源&#xff0c;我在这里采用的是微软商店中的TCP/UDP网络调试助手&#xff0…

ubuntu下修改hosts读写权限

ubuntu下修改hosts文件的操作&#xff1a; 由于需要在hosts文件下添加ip地址信息&#xff0c;但是初始情况下系统该文件为只读权限无法修改&#xff0c;具体操作如下所示&#xff1b; 1.cd到系统etc目录下&#xff0c;执行如下命令,此时会提示输入密码&#xff0c;直接输入回…

python28-Python的运算符之三目运算符

Python可通过if语句来实现三目运算符的功能&#xff0c;因此可以近似地把这种if语句当成三目运算符。作为三目运算符的f语句的语法格式如下 True_statements if expression else False_statements 三目运算符的规则是:先对逻辑表达式expression求值&#xff0c;如果逻辑表达式…

Java实现数据可视化的智慧河南大屏 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 数据模块 A4.2 数据模块 B4.3 数据模块 C4.4 数据模块 D4.5 数据模块 E 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的数据可视化的智慧河南大屏&#xff0c;包含了GDP、…

学习好并用好大模型

大模型是个好东西&#xff0c;学好并用好益处多多~ 1. 运用大模型服务我们的工作 运用大模型服务于工作&#xff0c;可以从以下几个方面着手&#xff1a; 知识管理与检索&#xff1a; 利用大模型强大的自然语言处理能力&#xff0c;建立企业内部的知识库系统。员工可以通过提问…

python flask 魔术方法

魔术方法作用_init_对象的初始化方法_class_返回对象所属的类_module_返回类所在的模块_mro_返回类的调用顺序&#xff0c;可以找到其父类&#xff08;用于找父类&#xff09;_base_获取类的直接父类&#xff08;用于找父类&#xff09;_bases_获取父类的元组&#xff0c;按它们…
最新文章