C/C++动态分配内存的几种方法

article/2025/9/14 23:42:14

  使用C/C++编程时,会经常动态分配内存,以便合理使用内存,本文主要讲述动态内存分配的几种方法及一些原理,理解不深刻之处欢迎指教。

引言

  为什么要进行动态内存分配?以数组为例,数组元素在内存中存储的地址是连续的。声明一个数组后,该数组需要的内存大小在程序编译时就被分配,但是该数组实际所需内存大小在程序运行时才知道,若运行时发现数组所需内存大于编译时的分配好的数组内存,就会报错,示例程序如下:

#include <stdio.h>
int main(void)
{int arr[3];for (int i = 0; i < 5; i++)scanf("%d", &arr[i]);for (int i = 0; i < 5; i++)printf("%d ", arr[i]);printf("\n");return 0;
}

  首先声明了有三个元素的数组arr,但是在实际输入时输入了5个元素,也就是说编译器在编译时给arr分配了3个int型大小的内存块,但是在运行时需要5个int型大小的内存块,就会报如下错误。
在这里插入图片描述

  因此人们采取了一个简单的方法,就是声明一个足够大的数组,例如int arr[1000]。但是该方法有以下缺点:
(1)若程序所需的数组元素个数大于1000,也会造成上述错误;
(2)若程序所需的数组元素个数只有5,会浪费很大的内存空间;
(3)若程序所需的数据元素个数大于1000,为了提高程序的鲁棒性,应该做出合理的响应,而不是简单报错。
  为了解决上述问题,就需要动态分配内存,所谓动态分配内存,通俗理解是需要多大的内存,就分配多大的内存。在C语言中,与动态内存分配有关的函数为malloc、calloc、realloc、free,这些函数在库文件<stdlib.h>中声明;C++中,与动态内存分配有关的运算符为new、delete。

malloc

  malloc是C语言提供的执行内存分配的函数。malloc函数原型为"void *malloc(size_t size);",当程序调用malloc函数时,malloc就从内存池中提取相应大小的连续内存块,并返回指向该内存块起始位置的指针。示例程序如下:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{int *p;int count;scanf("%d", &count);          //输入元素个数p = (int *)malloc(count*sizeof(int));//分配内存空间,将首地址赋给pif (p == NULL)                   //若分配失败,报错exit(-2);for (int i = 0; i < count; i++)scanf("%d", p + i);for (int i = 0; i < count; i++)printf("%d ", *(p + i));printf("\n");free(p);return 0;
}

  关于malloc函数,注意以下几点:
(1)malloc申请的内存是连续的,由于数组的内存也是连续的,因此二者有相通之处,*(p+i)可以表示为数组的第(i+1)个元素;
(2)如果内存池是空的,malloc会向操作系统请求得到更多的内存,然后进行分配;如果操作系统无法向malloc提供更多的内存,malloc就会返回NULL指针,NULL其实就是一个宏定义,值为0,因此对p的值检查是十分必要的,如果p为NULL,表示没分配到内存,自然就不能进行接下来的步骤了。
(3)观察函数原型"void *malloc(size_t size);"可知,malloc返回的是void *类型的指针,这是因为malloc无法得知程序用分配好的内存块存储什么类型的数据(例如int、char、double等),因此返回void *类型,而void *类型可以转为其他任何类型的指针,上述程序就将void *类型强制转换为int *类型,以便该内存块存储int型的数据。
(4)从指针角度看,因为指针存储的是变量的地址,是一个地址值,因此“p = (int )malloc(countsizeof(int))”这个操作可以理解为对指针p初始化。

calloc

  calloc也用于内存分配,函数原型为"void *calloc(size_t num_elements,size_t element_size);",示例程序如下:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{int *p;int count;scanf("%d", &count);p = (int *)calloc(count,sizeof(int));if (p == NULL)exit(-2);for (int i = 0; i < count; i++)printf("%d ", *(p + i));printf("\n");free(p);return 0;
}

  程序运行结果如下:
在这里插入图片描述
  该函数和malloc有以下区别:
(1)申请完内存块后,calloc将该内存块存储的值初始化为0,然后才返回指向该内存块起始位置的指针;
(2)两个函数请求内存大小的方式不同,可见参数列表。

realloc

  realloc主要用于修改已经分配的内存的大小,函数原型为“void *realloc(void *ptr,size_t new_size);”,ptr代表已经分配内存的首地址,new_size代表修改后的大小。若用于扩大一个内存块,该内存块原先的内容保留,新增加的内存添加到原先的内存块的后面,并且新增加的部分没有初始化;若用于缩小一个内存块,该内存块的尾部的部分内存被裁减掉,前面的部分内存的内容依然保留。示例程序如下:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{int *p,*newbase;int count;scanf("%d", &count);p = (int *)malloc(count*sizeof(int));if (p == NULL)exit(-2);for (int i = 0; i < count; i++)scanf("%d", p + i);for (int i = 0; i < count; i++)printf("%d ", *(p + i));printf("\n");newbase = (int *)realloc(p, 2*count*sizeof(int));if (newbase == NULL)exit(-2);for (int i = count; i < 2 * count; i++)scanf("%d", newbase + i);for (int i = 0; i < 2*count; i++)printf("%d ", *(newbase + i));printf("\n");free(newbase);return 0;
}

  程序运行结果如下:
在这里插入图片描述
  关于该函数,注意:若原先的内存块的大小无法改变,realloc将分配另一块指定大小的内存块,并将原先内存块的内容复制到新的内存块上。若发生这种情况,内存块的首地址就发生了改变,因此应使用新的指针接收realloc函数的返回值。

free

  当动态分配的内存不再需要时,应该将其释放掉,以便以后重新分配,若使用完不释放会引起内存泄漏。free函数用来释放malloc、calloc、realloc申请的内存空间,函数原型为“void free(void *ptr)”,ptr是指向要释放的内存块的指针,该函数没有返回值,free的参数若是NULL,则free不会产生任何效果。示例程序如下:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{int *p;p = (int *)calloc(5, sizeof(int));if (p == NULL)exit(-2);printf("地址和值分别为:%p %d\n", p, *p);for (int i = 0; i < 5; i++)printf("%d ", *(p + i));printf("\n");free(p);printf("释放后地址和值分别为:%p %d\n", p, *p);p = NULL;printf("地址为:%p\n", p);return 0;
}

  运行结果如下:
在这里插入图片描述

  注意:使用free释放的是内存块,而不是ptr这个指针变量,ptr的这个指针变量仍然指向该内存空间,只不过该内存空间的内容是毫无意义的是,是未定义的,为了防止以后程序不小心使用了它,要把它指向NULL。

new

new是C++的一个关键字,也是操作符,C语言并没有new,new也经常被用于动态内存分配,示例程序如下:

#include <iostream>
using namespace std;
int main(void)
{int *p, *q,*s;p = new int; //申请分配一个存储int型数据的内存块,相当于"p=(int *)malloc(sizeof(int));"q = new int(0); //申请分配一个存储int型数据的内存块,并初始化为0,相当于"q=(int *)calloc(sizeof(int))";s = new int[10]; //申请分配十个存储int类型数据的内存块,相当于"s=(int *)malloc(10*sizeof(int))";delete p;delete q;delete[] s;return 0;
}

  它和malloc有如下区别:
(1)new申请内存分配时无需指定内存块的大小,编译器会自己计算,malloc则需要使用sizeof等函数计算好内存块的大小;
(2)若申请成功,new会返回指定类型的指针,不需再进行类型转换;而malloc返回的是void *类型的,还需强制转换成我们需要的类型;
(3)若申请失败,new会抛出bac_alloc异常,而malloc会返回NULL。
  关于更详细的解释,可见博客动态内存分配、malloc与new的区别,这篇博客从更深层次的角度分析了malloc和new的区别。

delete

  new申请的内存块不被释放,也会造成内存泄露,C++主要使用delete来释放new申请的内存。delete用于释放new申请的单个元素分配的内存,delete[]用于释放new []申请的多个元素分配的内存,具体使用方法见上述程序。注意:使用delete释放的是内存块,而不是s这个指针变量,释放完后,s就变为随机值了,如果在接下来的程序中,没有给s赋新值就再调用s,由于s在内存中是随机值,就有可能指向重要地址,以致使系统崩溃,稳妥起见,如果delete之后程序还没结束,就将s的值赋为NULL。

补充

  内存的分配方式有以下四种:
(1)从静态存储区域分配,例如全局变量,这些内存在程序编译时就已分配,程序运行期间都存在;
(2)从栈上分配,例如局部变量,这些内存在函数结束时被自动释放;
(3)从堆上分配,例如malloc函数申请的内存,动态内存的生存期不会随着函数结束释放,由程序员决定;
(4)其他,例如常量、二进制代码等,这些内存在程序运行期间一直存在,程序结束后释放。


http://chatgpt.dhexx.cn/article/jbBVCAZC.shtml

相关文章

sadad

出版社&#xff1a; 河北少年儿童出版社 ISBN&#xff1a;12176804 版次&#xff1a;1 商品编码&#xff1a;12176804 包装&#xff1a;精装 丛书名&#xff1a; 幼儿家庭课堂 开本&#xff1a;12开 出版时间&#xff1a;2017-05-01 用纸&#xff1a;铜版纸 适读人群 &#xff…

SAADC

电流 :EasyDMA draws about 1.2 mA, and added to the 700 uASAADC current it sums to ~2 mA。和实测差不多 官方例程解析:TIMER + PPI +SAADC。 特征: 1、 支持8/10/12位分辨率,和14位过采样分辨率 2、 8通道:单端输入最多可同时配置8个通道 和 差分输入…

SAZS~

本文提出了一种新颖的形状感知零样本语义分割&#xff08;SAZS&#xff09;框架&#xff0c;利用大规模预训练视觉语言模型特征空间中丰富的先验知识&#xff0c;并通过在边界检测约束任务上进行联合训练来融合形状感知 论文链接&#xff1a;https://arxiv.org/abs/2304.08491…

SASSD

Structure Aware Single-stage 3D Object Detection from Point Cloud 文章&#xff1a;SA-SSD 代码&#xff1a;SA-SSD 这是来自香港理工大学和达摩院的一篇文章&#xff0c;一作是为在读的博士生&#xff0c;何晨航。通讯作者是张磊&#xff0c;香港理工大学的博导&#x…

Sarsa

基本概念 Sarsa Sarsa算法与Q-Learning算法极为相似&#xff0c;‘sarsa’五个字母的含义即s(当前状态)&#xff0c;a(当前行为)&#xff0c;r(奖励)&#xff0c;s(下一步状态)&#xff0c;a(下一步行为)&#xff0c;也就是说我们在进行这一步操作时已经想到当前s对应的a&…

反激电源

扶苗平衡&#xff1a;是针对电感的&#xff0c;不是针对变压器的&#xff1b;是电感稳态期间的情况&#xff0c;不是暂态期间的情况&#xff1b; 一个周期内&#xff0c;电感开通期间两端的电压乘以开通时间电感关断期间两端电压乘以关断时间。 对于反激变压器&#xff0c;其实…

Part-Ⅰ2. 稳态变换器分析原则(二)

2.4 Cuk电路分析 作为第二个示例&#xff0c;变换器可以实现类似buck-boost电路功能&#xff1a;升高或降低电压幅值&#xff0c;并且转换极性。其电路如如下。 该转换器通过电容进行能量传输。当开关打到位置2时&#xff0c;电容 C 1 C_1 C1​通过 L 1 L_1 L1​连到输入电源…

buck-boost基本模型

1.电容模型 2.电感模型 3.伏秒平衡 4.电容电感 5.BUCK 6.boost 7.参考资料 《开关电源的基本概念和分析方法》

2、Principles of Steady-State Converter Analysis

2、Principles of Steady-State Converter Analysis 伏秒平衡与安秒平衡 在电路平衡时&#xff0c;作为存储元件的电感与电容&#xff0c;其储存的能量不可能无穷大&#xff0c;必然会稳在一个稳定值。 稳定后必然有在一个开关周期内有 所以 在求解时&#xff0c;只要根据…

1dB压缩点和三阶交调点、相位差与延时

1dB压缩点与三阶交调点 要知道放大器是一个非线性系统&#xff0c;传输函数基本用泰勒级数表示 如果输入信号幅度很小&#xff0c;那么上式中2次及以上的项就可以忽略而成为小信号的情况。在许多情况下我们可以忽略3次以上的项。 如果输入一个正弦信号 1、可以看到一个单频率…

半桥电路注意事项

应注意的几点问题 偏磁问题 原因&#xff1a;由于两个电容连接点A的电位是随Q1、Q2导通情况而浮动的&#xff0c;所以能够自动的平衡每个晶体管开关的伏秒值&#xff0c;当浮动不满足要求时&#xff0c;假设 Q1、Q2具有不同的开关特性&#xff0c;即在相同的基极脉冲宽度tt1下&…

有关DC/DC和LDO 的详细介绍以及两者的对比----之DC/DC篇

目录 DC/DC工作原理 电感电压伏秒平衡定律 开关电源的三种基本拓扑 同步整流技术 DC/DC电源调制方式 DC/DC芯片的内部构造 DC/DC电路的硬件设计 总结一下DC/DC和LDO的原理&#xff0c;区别和应用&#xff0c;以下内容部分为自己原创&#xff0c;部分在网上找的资料并加上…

BUCK中的电感值---开关电源篇(4)

前一篇&#xff0c;BUCK电路&#xff0c;了解到功率电感中的电流是呈现为以开关频率为周期的伏秒平衡态。 即dI * L dV * dt 1&#xff09; 相同伏秒变化的情况下&#xff0c;电感的值如果越大&#xff0c;则电感上电流的变化量会越小。这个电流的变化量有个专用名称叫纹波电…

SVPWM所需要掌握的一些定理

1&#xff0c;正弦定理。 2.伏秒平衡&#xff08;不懂&#xff09; 伏秒平衡&#xff1a; 又称伏秒平衡&#xff0c;是指开关电源稳定工作状态下&#xff0c;加在电感两端的电压乘以导通时间等于关断时刻电感两端电压乘以关断时间&#xff0c;或指在稳态工作的开关电源中电感…

开关电源环路稳定性分析(2)-从开环到闭环

大家好&#xff0c;这里是大话硬件。 在上一节中&#xff0c;基于欧姆定律&#xff0c;基尔霍夫定律&#xff0c;伏秒平衡这些已知的知识点&#xff0c;可以推导出Buck变换器的输入输出关系。 今天这一节&#xff0c;我们还是从全局的概念来解析开关电源。 1. 运放和开关电源…

GaN图腾柱无桥 Boost PFC(单相)七-PFC占空比前馈

PFC占空比前馈概述 单纯依靠控制环路的PI调节器进行控制调节&#xff0c;控制环路的带宽会比较窄。另外&#xff0c;由于调节速度不够快&#xff0c;也将影响整个系统的动态性能。采用占空比前馈控制和反馈控制同时调节的数字控制技术&#xff0c;降低了对控制环路参数的要求。…

升压BOOST电路和降压BUCK电路最容易的理解

升压电路框图 首先在了解BOOST电路时&#xff0c;要学会如何分析最简单的升压电路框图。如图&#xff1a; 首先识别每个元件基本功能&#xff1a;电感&#xff1a;储能i电感&#xff1b;MOS管&#xff1a;开关作用&#xff1b;二极管&#xff1a;续流&#xff1b;电容&#x…

DC-DC变换器(DCDC Converter / Switched-mode Power Supply)简介

文章目录 针对B站视频&#xff0c;截取ppt做的完整笔记&#xff0c;视频地址附在下方0、DC-DC变换器概述1、DC-DC变换器的基本结构BuckBoostBuck-BoostBoost-Buck小结 2、换流与特性分析分析Buck电路分析Boost电路分析Buck-Boost电路&#xff08;前级Buck后级Boost&#xff09;…

电力电子技术---直流直流交换变换电路

直流-直流交换技术 文章目录 直流-直流交换技术DC-DC变换电路的工作原理脉冲调制方式Buck电路基本输入输出关系电感伏秒平衡和电容充电平衡电感的伏秒平衡电容安秒平衡 DC-DC变换电路的工作原理 DC-DC变换电路&#xff08;直流斩波电路&#xff09;&#xff1a; 作用&#xf…

升降压斩波电路(电力电子技术)

1.电路原理图&#xff0c;开关器件为MOSFET 2.工作原理 电感L的电流和电压波形 3.输出电压的推导 推导方式一 推导方式二&#xff0c;根据电感伏秒平衡 4.练习题 练习题1 解题过程 练习题二 解题过程