C/C++ 动态内存分配与它的指针变量
一、什么是内存的动态分配
全局变量分配在内存中的静态存储区。局部变量(包括形参)分配在内存中的动态存储区,这个存储区是一个称为栈的区域。除此之外,C语言还允许建立内存动态分配区域,以存放一些临时用的数据,这些数据不必在程序的声明部分定义,也不必等到函数结束时才释放,而是需要时随时开辟,不需要时随时释放。这些数据是存放在一个特别的自由存储区,称为堆区。可以根据需要向系统申请所需大小的空间。由于未在声明部分定义它们为变量或数组,因此不能通过变量名或数组名去引用这些数据,只能通过指针来引用。
也就是说,全局变量分配于静态存储区,局部变量分配于栈,动态内存分配在堆。
二、怎样建立内存的动态分配
对于内存的动态分配是通过系统提供的库函数来实现的,主要有malloc,calloc,realloc,free这四个函数。
1.用malloc函数开辟动态内存
malloc的函数原型为:
void *malloc(unsigned int size);
malloc函数的作用是:
在内存的动态存储区中分配一个长度为size的连续空间。形参size的类型定为无符号整型(不允许为负数)。此函数的值(即“返回值”)是所分配区域的第一个字节的首地址,或者说,此函数是一个指针型函数,返回的指针指向该分配域的第一个字节。如:
malloc(100);
//开辟100字节的临时分配域,函数值为其第一个字节的地址。
注意指针的基类型为void,即不指向任何类型的数据,只提供一个地址。如果此函数未能成功执行(例如内存空间不足),则返回空指针(NULL),失败只有一种情况,就是申请的内容太大,超出堆能提供的最大连续空间。
2.用calloc函数开辟动态内存
calloc的函数原型为:
void*calloc(unsigned n,unsigned size);
calloc的函数的作用是:
在内存的动态存储区中分配n个长度为size的连续空间,这个空间一般比较大,足以保存一个数组。
用calloc函数可以为一维数组开辟动态内存存储空间,n为数组元素个数,每个元素长度为size。这就是动态数组。函数的指针指向所分配域的第一个字节,此函数的值(即“返回值”)是所分配区域的第一个字节的首地址;如果不成功,返回空指针(NULL)。如:
p=calloc(50,4);
//开辟50个长度为4个字节的临时分配域,把首地址赋给指针变量p
calloc和malloc最大的区别为:申请完空间之后calloc会将每个元素的值直接置为0。
3.用realloc函数重新分配动态内存
realloc函数的原型:
void *realloc(void*p,unsigned int size);
参数的意义:p:旧内存的地址;size:新申请的内存大小,以字节为单位
realloc函数的作用是:
如果已经通过malloc函数或calloc函数获得了动态内存空间,想改变其大小,可以用realloc函数重新分配。用realloc函数将p所指向的动态内存空间的大小改变为size。p的值不变。函数值成功返回时返回新的动态内存的首地址,如果重分配不成功,返回空指针(NULL)。失败只有一种情况就是申请的内容太大,超出堆能提供的最大连续空间。如:
realloc(p,50);
//将p指向的动态内存空间的大小改变为50字节
用malloc实现realloc扩容:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main()
{int n = 10;int *p=(int*)malloc(n * sizeof(int));assert(p != NULL);int i;for (i = 0; i < n; i++){p[i] = i;}for (i = 0; i < n; i++){printf("%d ", p[i]);}printf("\n");//1发现p申请的太少,于是重新申请int*q=(int *)malloc(2* n * sizeof(int));//1申请新内存//2搬家for (i = 0; i < 2*n; i++){q[i] =i;}for (i = 0; i < 2*n; i++){printf("%d ", q[i]);}free(p);//3释放p的内存p = q;//4接收新内存q = NULL;//...后面可以继续使用preturn 0;
}

realloc实现扩容:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main()
{int n = 10;int* p = (int*)malloc(n * sizeof(int));assert(p != NULL);int i;for (i = 0; i < n; i++){p[i] = i;}for (i = 0; i < n; i++){printf("%d ", p[i]);}printf("\n");//1发现p申请的太少,于是重新申请p = (int*)realloc(p, 2 * n * sizeof(int));for (i = 0; i < 2 * n; i++){p[i] = i;}//2搬家for (i = 0; i < 2 * n; i++){printf("%d ", p[i]);}//...后面可以继续使用pfree(p);return 0;
}

4.用free函数释放动态存储区
free函数的原型:
void free(viod*p);
free函数的作用是:
释放指针变量p所指向的动态内存空间,使这部分空间能重新被其他变量使用。p应是最近一次调用calloc或malloc函数时得到的函数返回值。free函数无返回值。如:
free(p);
//释放指针变量p所指向的已分配的动态内存空间
free崩溃的原因:
1.p移动了(p++),因为申请p的时候有一个n的大小,如果p移动,找不到头信息
2.找不到尾信息
3.重复释放了一段内存
以上4个函数malloc,calloc,realloc,free的声明都在stdlib.h的头文件中,在用到这些函数时应该用#include<stdlib.h>指令把stdlib.h头文件包含在程序文件中。
三、void指针类型
C99允许使用基类型为void的指针类型。可以定义一个基类型为void的指针变量(即void*型变量),它不指向任何类型的数据。
注意:不要把“指向void类型”理解为能指向“任何类型”的数据,而应理解为“指向空类型”或“不指向确定的类型”的数据。在将它的值赋给另一指针变量时由系统对它进行类型转换,使之适合于被赋值的变量的类型。
例如:
int main()
{int a = 3; //定义a为整型变量int* p1 = &a;//p1指向int型变量char* p2;//p2指向char型变量void* p3;//p3为无类型指针变量(基类型为void型)p3 = (void*)p1;//将p1的值转换为void*类型,然后赋值给p3p2 = (char*)p3;//将p3的值转换为char*类型,然后赋值给p2printf("%d", *p1);//合法,输出整型变量a的值void* p3 = &a; printf("%d", *p3);//错误,p3是无指向的,不能指向a
}
说明:
地址信息应该包含位置信息和基类型的信息。 一定要注意基类型的信息,即存放存放在以此地址标志的存储单元中的数据类型,否则无法实现对数据的存取。所以对于void*类型的指针,这种指针无指向,在这种无指向的地址所标志的存储单元中是不可以存储任何数据的,也就是说无法通过这种地址对内存存取数据。
什么情况下会用到void*类型的指针:
在调用动态存储分配函数(如malloc、calloc、realloc函数)时会用到void*类型的指针。用户用这些函数开辟动态存储区时,希望获得此动态存储区的起始地址,以便利用该动态存储区。
C99规定malloc、calloc、realloc函数返回void*指针,使其“无指向”,这种指针称为“空类型指针”,它不指向任一种具体的数据类型,只提供一个地址。这是C有关地址应用的一种特殊情况。
这种空类型指针在形式上和其他指针一样,遵循C语言对指针的有关规定,它也有基类型,只是它的基类型是void,可以这样定义:
void*p; //定义p是void*型的指针变量
void*型指针代表“无指向的地址”,这种指针不指向任何类型的数据。不能企图通过它存取数据,在程序中它只是过渡性的,只有转换为有指向的地址,才能存取数据。
四、建立动态内存分配区和使用void指针
【例题】建立动态数组,输入5个学生的成绩,另外用一个函数检查其中有无低于60分的,输出不合格的成绩。
【思路】用malloc开辟一个动态自由区域,用来存放5个学生的成绩,会得到这个动态域的第一个字节的地址,他的基类型是void型。用一个基类型是int的指针变量p来指向动态数组的各元素,并输出它们的值。但必须先把malloc函数返回的void指针转换为整型指针,然后赋给p1。
#include <stdio.h>
#include <stdlib.h> //程序中用了malloc函数,应包含stdlib.h
void check(int* p)//定义check函数,形参是int*指针
{printf("不合格的成绩为:");for (int i = 0; i < 5; i++){if (p[i] < 60)printf("%d ", p[i]);//输出不合格成绩}printf("\n");
}
int main()
{int* p1 = (int*)malloc(5 * sizeof(int)); //p1是int型指针,开辟动态内存,将地址转换为int*型,然后放在p1中for (int i = 0; i < 5; i++){scanf("%d", &p1[i]);//输入5个学生的成绩}check(p1);//调用check函数free(p1);return 0;
}

五、断言assert
一种比较保守的编程方式:每一次都要验证动态申请内存的返回值是否为空,这里就需要用到断言assert,assert函数的声明都在assert.h的头文件中,在用到这个函数时应该用#include<assert.h>指令把assert.h头文件包含在程序文件中。
【例题】输出n个连续自然数中的所有素数
void Getprimer(int n)
{int* p = (int*)malloc(n * sizeof(int));//堆assert(p != NULL);for (int i = 0; i < n; i++){p[i] = 1;}p[1] = p[0] = 0;//0和1不是素数for (int i = 2; i < n; i++){for (int j = i + 1; j < n; j++){if (j % i == 0)p[j] = 0;}}for (int i = 2; i < n; i++){if (p[i] == 1){printf("%d是素数\n", i);}}free(p);
}
int main()
{int n;printf("请输入n的大小:");scanf("%d", &n);Getprimer(n);return 0;
}
相关文章:
C/C++ 动态内存分配与它的指针变量
一、什么是内存的动态分配 全局变量分配在内存中的静态存储区。局部变量(包括形参)分配在内存中的动态存储区,这个存储区是一个称为栈的区域。除此之外,C语言还允许建立内存动态分配区域,以存放一些临时用的数据&…...
UE5初学者快速入门教程
虚幻引擎是一系列游戏开发工具,能够将 2D 手机游戏制作为 AAA 游戏机游戏。虚幻引擎 5 用于开发下一代游戏,包括Senuas Saga: Hellblade 2、Redfall(来自 Arkane Austin 的合作射击游戏)、Dragon Quest XII: The Flames of Fate、…...
论文笔记--FEDERATED LEARNING: STRATEGIES FOR IMPROVING COMMUNICATION EFFICIENCY
论文笔记--FEDERATED LEARNING: STRATEGIES FOR IMPROVING COMMUNICATION EFFICIENCY 1. 文章简介2. 文章概括3 文章重点技术3.1 联邦学习(federated learning, FL)3.2 Structured updates3.3 Sketched Update 4. 文章亮点5. 原文传送门 1. 文章简介 标题:FEDERATE…...
STM32MP157驱动开发——按键驱动(异步通知)
文章目录 “异步通知 ”机制:信号的宏定义:信号注册 APP执行过程驱动编程做的事应用编程做的事异步通知方式的按键驱动程序(stm32mp157)button_test.cgpio_key_drv.cMakefile修改设备树文件编译测试 “异步通知 ”机制: 信号的宏定义&#x…...
医疗器械维修工程师心得
彩虹医械维修技能班9月将开展本年第三期长期班,目前咨询人员也陆续多了起来,很多刚了解到医疗行业的,自身也没有多少相关的基础,在咨询时会问到没有基础能否学的会? 做了这行业的都知道,无论多么复杂的设备…...
Vue3 Radio单选切换展示不同内容
Vue3 Radio单选框切换展示不同内容 环境:vue3tsviteelement plus 技巧:v-if,v-show的使用 实现功能:点击单选框展示不同的输入框 效果实现前的代码: <template><div class"home"><el-row …...
FreeRTOS之二值信号量
什么是信号量? 信号量(Semaphore),是在多任务环境下使用的一种机制,是可以用来保证两个或多个关键代 码段不被并发调用。 信号量这个名字,我们可以把它拆分来看,信号可以起到通知信号的作用&am…...
ChatGPT API进阶调用指南
原文:ChatGPT API进阶调用指南 ChatGPT API 进阶调用指南 ChatGPT API 是基于 OpenAI 的 GPT模型的一个强大工具,可以用于构建各种对话式应用。以下是一些使用 Markdown 语法的进阶调用指南,以帮助您更好地利用 ChatGPT API。 设置用户角色…...
人工智能术语翻译(四)
文章目录 摘要MNOP 摘要 人工智能术语翻译第四部分,包括I、J、K、L开头的词汇! M 英文术语中文翻译常用缩写备注Machine Learning Model机器学习模型Machine Learning机器学习ML机器学习Machine Translation机器翻译MTMacro Average宏平均Macro-F1宏…...
kubernetes持久化存储卷
kubernetes持久化存储卷 kubernetes持久化存储卷一、存储卷介绍二、存储卷的分类三、存储卷的选择四、本地存储卷之emptyDir五、本地存储卷之 hostPath六、网络存储卷之nfs七、PV(持久存储卷)与PVC(持久存储卷声明)7.1 认识pv与pvc7.2 pv与pvc之间的关系7.3 实现nfs类型pv与pvc…...
【Rust笔记】意译解构 Object Safety for trait
意译解构Object Safety for trait 借助【虚表vtable】对被调用成员函数【运行时内存寻址】的作法允许系统编程语言Rust模仿出OOP高级计算机语言才具备的【专用多态Ad-hoc Polymorphism】特性。 计算机高级语言中的“多态”术语是一个泛指。它通常可被细化为 基于继承关系的“子…...
Spring Boot单元测试入门指南
Spring Boot单元测试入门指南 JUnit是一个成熟和广泛应用的Java单元测试框架,它提供了丰富的功能和灵活的扩展机制,可以帮助开发人员编写高质量的单元测试。通过JUnit,开发人员可以更加自信地进行重构、维护和改进代码,同时提高代…...
《面试1v1》如何能从Kafka得到准确的信息
🍅 作者简介:王哥,CSDN2022博客总榜Top100🏆、博客专家💪 🍅 技术交流:定期更新Java硬核干货,不定期送书活动 🍅 王哥多年工作总结:Java学习路线总结…...
2023秋招面试题持续更新中。。。
目录 1.八股文渐进式MVVM三次握手,四次挥手viteajax组件化和模块化虚拟dom原理流程浏览器内核浏览器渲染过程回流和重绘nextTick 2.项目相关1.声明式导航和编程式导航重写push和replace方法:性能优化图片懒加载路由懒加载 http请求方式 1.八股文 渐进式…...
Java | 数组排序算法
一、冒泡排序 冒泡排序的基本思想是对比相邻的元素值,如果满足条件就交换元素值,把较小的元素移到数组前面,把较大的元素移到数组后面(也就是交换两个元素的位置),这样较小的元素就像气泡一样从底部升到顶…...
android studio 连接SQLite数据库并实现增删改查功能
功能代码及调试代码 package com.example.bankappdemo;import android.annotation.SuppressLint; import android.content.ContentValues; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.util.Log; import android.view.View; im…...
跑步适合戴什么样的耳机、最好的跑步耳机推荐
每个人对于运动的方式都不尽相同,但大多数热爱运动的朋友都离不开音乐的陪伴。运动和带有节奏感的音乐能够激发我们更多的热情和动力。特别是在夏日的时候,我非常喜欢跑步。在酷热的天气里,如果没有音乐的伴随,跑步会变得单调乏味…...
物联网的通信协议
物联网的通信协议 目录 物联网的通信协议一、UART串口通信1.1 串口通信1.2 异步收发1.3 波特率1.4 串口通信协议的数据帧1.5 优缺点1.5.1 优点1.5.2 缺点 二、I^2^C2.1 I^2^C2.2 I^2^C2.3 数据有效性2.4 起始条件S和停止条件P2.5 数据格式2.6 协议数据单元PDU2.7 优缺点2.7.1 优…...
【业务功能篇56】SpringBoot 日志SLF4J Logback
3.5.1 日志框架分类与选择 3.5.1.1 日志框架的分类 日志门面 (日志抽象)日志实现JCL(Jakarta Commons Logging) SLF4J(Simple Logging Facade for Java)Jul(Java Util Logging) , Log4j , Log4j2 , Logback 记录型日志框架 Jul (Java Util Logging):JDK中的日志…...
leetcode 53. 最大子数组和
2023.7.28 要求找最大和的 连续子数组, 我的思路是用一个temp记录局部最优值,用ans记录全局最优值。 然后在每次for循环进行一个判断:当前遍历元素temp值 是否大于当前遍历元素的值,如果大于,说明temp值是帮了正忙的&a…...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
