《掌握 C/C++ 动态内存管理,让编程更高效灵活》

news2025/1/7 15:51:54

这里写目录标题

  • 一、回顾C/C++内存分布
    • 1. 三道基础的练习题
    • 2. 内存区域划分图
  • 二、C 语言中动态内存的管理方式(malloc/calloc/realloc/free)
    • 1. malloc() 和 calloc() 的区别和注意事项
    • 2. realloc() 的用法和注意事项
  • 三、C++ 中的动态内存管理方式(new/delete)
    • 1. new 和 delete 操作符的使用方法
    • 2. new 和 delete 操作自定义类型
    • 3. new/delete 和 malloc/free 的区别
    • 4. operator new 和 operator delete 函数(了解)
    • 5. new 和 delete 的实现原理
    • 6. 定位 new(了解)
  • 四、与内存有关的常见面试题
    • 1. malloc/free 和 new/delete 的区别
    • 2. 什么是内存泄漏?内存泄漏的危害

一、回顾C/C++内存分布

1. 三道基础的练习题

  下面通过一段代码和内存分布相关的代码和一些题目回顾一下前面 C 语言学习的内存分布。
在这里插入图片描述

  下面是上面题目的答案:

  1. A A A C C
    A A A D A B
  2. 40 5 4 4/8 4 4/8
  3. sizeof 计算后面变量或者类型所占内存空间的大小,单位字节;
    strlen 计算从后面字符地址(char*)开始的字符个数,直到遇到第一个空字符(不包括第一个空字符)。

2. 内存区域划分图

在这里插入图片描述
  栈中的空间基本上都是用来开辟函数栈帧的,一次性开辟一块栈帧,函数中所创建的局部变量都在其中。栈是向下增长的,因为栈从高地址开始往低地址使用。可以想象把一个木桶开口朝下,然后往桶子里塞东西,这样桶子的容量就是从高到底使用。

  堆中的空间在 C 语言中通过使用函数 malloc() 申请空间和函数 free() 释放空间从而来管理。堆是向上增长的,就是往开口向上的桶子塞东西。

 数据段也叫静态区,专门用来存放静态数据(static)和全全局数据。

  代码段也叫常量区,一般用来存放可执行的代码和字面值常量。

二、C 语言中动态内存的管理方式(malloc/calloc/realloc/free)

  C 语言中 malloc() 函数和 calloc() 函数的作用是开辟空间,realloc() 函数的作用是扩容,而 free() 函数的作用是释放空间。

1. malloc() 和 calloc() 的区别和注意事项

// malloc() 和 calloc() 的区别
int* pa = (int*)malloc(sizeof(int));
int* pb = (int*)calloc(sizeof(int), 1);
cout << "*pa = " << *pa << endl;
cout << "*pb = " << *pb << endl;

  程序的运行结果如下:
在这里插入图片描述
  从上面的测试中可以得出 malloc() 和 calloc() 有两个区别:
(1)使用方法的不同:
  malloc() 函数接受一个参数,该参数表示开辟空间的大小;而 calloc() 接受两个参数,第一个参数表示开辟空间的大小,第二个参数表示开辟空间的个数。

(2)对空间内容的处理不同:malloc() 函数对空间不做处理,开辟出来的空间中的值是随机值;而 calloc() 函数把空间的每个字节初始化为 0。

注意事项:
1)当使用这两个函数申请空间时,需要对申请结果进行判断,如果返回空指针(nullptr)则表示申请失败;
2)该两个函数都返回 void* 指针,所以要对返回结果进行强制类型转换成所需的指针。

  完整的使用方法如下:

// malloc()
int* pa = (int*)malloc(sizeof(int));
// 检查
if (nullptr == pa)
{
	perror("malloc: ");
	exit(-1);
}

// calloc() 
int* pb = (int*)calloc(sizeof(int), 1);
// 检查
if (nullptr == pb)
{
	perror("calloc: ");
	exit(-1);
}

2. realloc() 的用法和注意事项

  realloc() 函数的作用是对一个已经开辟的动态内存进行扩容。该函数的函数原型如下:

// realloc() 函数原型
void* realloc(void *ptr, size_t size)

第一个参数是需要扩容的动态内存空间的首地址,第二个参数是扩容后的总空间大小(单位字节)。扩容完毕之后返回扩容后的内存空间的首地址(void*)。

注意事项:
(1)需要对扩容返回的地址进行检查,若为 nullptr 则扩容失败;
(2)如果原空间后面的空间足够,则会在原空间的后面直接扩容,扩容后和扩容前的首地址相同;如果原空间后面的空间不够,则会在堆中找一块新的空间,把原空间的内容拷贝到新空间,销毁原空间。
(3)最好是使用一个新的指针变量接收扩容后的地址,在检查之后把该地址赋值给原空间的指针变量。

  完整的使用方法如下:
在这里插入图片描述
可以看到本次使用 realloc() 函数进行扩容不是在原空间之后进行扩容,而是寻找了一个新的空间。

三、C++ 中的动态内存管理方式(new/delete)

  虽然 C 语言中的 malloc() 和 free() 仍可以在 C++ 中继续使用,但是在某些地方上这两个函数还是无能为力。所以 C++ 提出了自己的内存管理方式——new和delete操作符。

1. new 和 delete 操作符的使用方法

  new 和 delete 操作符的使用方法与 C 中的 malloc() 和 free() 还是有一些差别的。

// 申请单个空间
int* pa = new int;
// 释放多个空间
delete pa;

// 申请多个空间
int* arr = new int[10];
// 释放多个空间
delete[]pa;

// 申请单个空间并初始化
int* pc = new int(10);
delete pc;

// 申请多个空间并初始化
int* pd = new int[10]{1, 2, 3, 4};
delete[]pd;

  申请单个空间时:new 类型,对应的释放:delete 指针;申请多个空间时:new 类型[个数],对应的释放,delete[]指针。切记一定要配对使用,不要混淆。

  可以看到使用 new 开辟空间时,只需要传递类型和个数即可,大小和返回类型 new 操作符会自己进行计算和转化。且开辟单个空间可以使用圆括号对空间初始化;开辟多个空间时可以使用花括号对空间进行初始化。

在这里插入图片描述

2. new 和 delete 操作自定义类型

  C++ 使用 new 和 delete 而不是用 C 的 malloc() 和 free() 最重要的一点就是对于自定义类型的处理。new 和 delete 在对自定义类型进行申请空间和释放空间时会分别调用该自定义类型的构造函数的析构函数。而 malloc() 和 free() 只是单纯的开辟空间和释放空间。

// 头文件
#include <iostream>

// using 声明
using std::endl;
using std::cout;
using std::cin;

// A 类声明
class A
{
private:
	int a;

public:
	A();
	~A();
};

// A 类成员函数定义
A::A()
	: a(0)
{
	cout << "A()" << endl;
}

A::~A()
{
	cout << "~A()" << endl;
}

int main()
{
	// 开辟单个空间
	cout << "单个空间:\n";
	cout << "new:\n";
	A* p1 = new A;
	delete p1;
	cout << "\nmalloc():\n";
	A* p2 = (A*)malloc(sizeof(A));
	free(p2);

	// 开辟多个空间
	cout << "\n多个空间\n";
	cout << "new:\n";
	A* arr1_A = new A[3];
	delete[]arr1_A;

	cout << "\nmalloc():\n";
	A* arr2_A = (A*)malloc(sizeof(A) * 3);
	free(arr2_A);

	return 0;
}

  程序的运行结果如下:
在这里插入图片描述
  通过上面的代码及运行结果可以得出,new 和 delete 在对自定义类型创建和销毁空间时会分别调用该类的构造函数(默认的)和析构函数。而 malloc() 和 free() 只是单纯的开辟和销毁空间。

  而 C++ 最重要的内容之一就是类和对象,所以 malloc() 和 free() 不适合 C++ 的发展,需要新增 new 和 delete 操作符来。

3. new/delete 和 malloc/free 的区别

(1)new 在创建空间的时候可以初始化,并且在处理自定义类型时还会调用构造函数;而 malloc 只是开辟空间,不进行任何其他操作;
(2)delete 对自定义类型进行释放空间时会调用析构函数;而 free 只释放空间,不进行其他操作;
(3)new 和 delete 在申请单个空间和多个空间上的用法不同,且需要配对使用;而 malloc 和 free 不需要;
(4)new 在创建空间的时候不需要传递空间大小,也不需要强制类型转换,只需要传递空间类型和数量。

4. operator new 和 operator delete 函数(了解)

  new 和 delete 是 C++ 中在堆上申请和释放空间使用的操作符,operator new 和 operator delete 是 C++ 提供的全局函数,new 和 delete 操作符在底层分别调用 operator new 和 operator delete 全局函数来申请和释放空间。
在这里插入图片描述
  从上面的代码可以看出,operator new 和 operator delete 实际上还是通过 malloc 申请空间和 free 释放空间,只不过为了适应 C++ 添加了一些其他的操作。

5. new 和 delete 的实现原理

  在处理内置类型时,new/delete 和 malloc/free 几乎没有区别,只是 new 和 delete 在创建和释放单个对象和多个对象的使用方法稍有不同。

  对于自定义类型:

(1)new 的原理:
a. 调用 operator new 函数申请空间;
b. 在申请的空间上面执行构造函数完成对象的构造。

(2)delete 的原理
a. 调用该类的析构函数完成对象的清理;
b. 调用 operator delete 函数释放空间。

(3)new T[N] 的原理
a. 调用 operator new[] 函数,在 operator new[] 函数中实际调用 operator new 函数完成 N 个对象空间的申请;
b. 在申请的空间上面执行 N 次构造函数完成 N 个对象的构造。

(4)delete[] 的原理
a. 调用 N 次析构函数完成 N 个对象的清理;
b. 调用 operator delete[] 函数,在 operator delete[] 函数中实际调用 operator delete 函数释放 N 个对象的空间。

6. 定位 new(了解)

  这里了解一下即可,现阶段基本上用不上这个定位 new。
在这里插入图片描述

四、与内存有关的常见面试题

1. malloc/free 和 new/delete 的区别

(1)malloc/free 是函数,而 new/delete 是操作符;
(2)malloc 申请空间不能初始化,new 可以初始化;
(3)malloc 申请空间需要传递申请空间的大小,还需要对返回类型进行强制类型转换,而 new 只需要传递申请空间的类型,如果申请多个对象需要在[]中填写申请个数;
(4)malloc 申请失败返回空指针(nullptr),new 申请失败捕捉异常;
(5)new/delete 在对自定义类型申请空间和释放空间时会调用其构造函数和析构函数,而 malloc/free 不会调用。

2. 什么是内存泄漏?内存泄漏的危害

  内存泄漏通常指的是在堆上申请的空间使用完了之后没有释放。内存泄漏并不是物理上的消失,而是申请空间之后这块空间的使用权限暂时归程序员,但是由于忘记了释放空间把权限归还系统,导致系统能使用的空间减少。

  如果长期运行的程序出现内存泄漏,影响很大,因为每次运转一遍程序都会泄露部分内存,随着程序次数的不断运行,泄露的内存越来越大,可用的内存越来越少,导致程序越来越卡。

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

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

相关文章

网络安全抓包

#知识点&#xff1a; 1、抓包技术应用意义 //有些应用或者目标是看不到的&#xff0c;这时候就要进行抓包 2、抓包技术应用对象 //app,小程序 3、抓包技术应用协议 //http&#xff0c;socket 4、抓包技术应用支持 5、封包技术应用意义 总结点&#xff1a;学会不同对象采用…

今日头条ip属地根据什么显示?不准确怎么办

在今日头条这样的社交媒体平台上&#xff0c;用户的IP属地信息对于维护网络环境的健康与秩序至关重要。然而&#xff0c;不少用户发现自己的IP属地显示与实际位置不符&#xff0c;这引发了广泛的关注和讨论。本文将深入探讨今日头条IP属地的显示依据&#xff0c;并提供解决IP属…

CSS3——3. 书写格式二

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title></head><body><!--css书写&#xff1a;--><!--1. 属性名:属性值--><!--2.属性值是对属性的相关描述--><!--3.属性名必须是…

C# OpenCV机器视觉:双目视觉-深度估计

在一个阳光欢快得仿佛要蹦迪的日子里&#xff0c;阿强像个即将踏上神秘星际旅行的宇航员&#xff0c;雄赳赳气昂昂地坐在实验室那张堆满奇奇怪怪小玩意儿的桌子前。桌上&#xff0c;两台摄像头宛如两个严阵以待的机甲战士&#xff0c;镜头闪烁着冷峻的光&#xff0c;仿佛在向阿…

网络IP协议

IP&#xff08;Internet Protocol&#xff0c;网际协议&#xff09;是TCP/IP协议族中重要的协议&#xff0c;主要负责将数据包发送给目标主机。IP相当于OSI&#xff08;图1&#xff09;的第三层网络层。网络层的主要作用是失陷终端节点之间的通信。这种终端节点之间的通信也叫点…

springboot566健美操评分系统(论文+源码)_kaic

摘 要 健美操评分系统采用B/S架构&#xff0c;数据库是MySQL。系统的搭建与开发采用了先进的JAVA进行编写&#xff0c;使用了springboot框架。该系统从三个对象&#xff1a;由管理员、裁判员和用户来对系统进行设计构建。主要功能包括首页&#xff0c;个人中心&#xff0c;裁…

【深度学习之空洞卷积】空洞卷积和普通卷积的比较包括哪些优势?从感受野、计算复杂度方面分析。

【深度学习之空洞卷积】空洞卷积和普通卷积的比较包括哪些优势&#xff1f;从感受野、计算复杂度方面分析。 【深度学习之空洞卷积】空洞卷积和普通卷积的比较包括哪些优势&#xff1f;从感受野、计算复杂度方面分析。 文章目录 【深度学习之空洞卷积】空洞卷积和普通卷积的比…

【机器遗忘之UNSIR算法】2023年IEEE Trans期刊论文:Fast yet effective machine unlearning

1 介绍 年份&#xff1a;2023 期刊&#xff1a;IEEE Transactions on Neural Networks and Learning Systems 引用量&#xff1a;170 Tarun A K, Chundawat V S, Mandal M, et al. Fast yet effective machine unlearning[J]. IEEE Transactions on Neural Networks and Le…

VSCode 在Windows下开发时使用Cmake Tools时输出Log乱码以及CPP文件乱码的终极解决方案

在Windows11上使用VSCode开发C程序的时候&#xff0c;由于使用到了Cmake Tools插件&#xff0c;在编译运行的时候&#xff0c;会出现输出日志乱码的情况&#xff0c;那么如何解决呢&#xff1f; 这里提供了解决方案&#xff1a; 当Settings里的Cmake: Output Log Encoding里设…

程序的环境(预处理详解)

一.程序的翻译环境和执行环境 在ANSI C&#xff08;标准c&#xff09;的任何一种实现中&#xff0c;存在两个不同的环境。 计算机是能够执行二进制指令的&#xff0c;但是我们写出的c语言代码是文本信息&#xff0c;计算机不能直接理解 第1种是翻译环境&#xff0c;在这个环境…

Kafka 消费者专题

目录 消费者消费者组消费方式消费规则独立消费主题代码示例&#xff08;极简&#xff09;代码示例&#xff08;独立消费分区&#xff09; offset自动提交代码示例&#xff08;自动提交&#xff09;手动提交代码示例&#xff08;同步&#xff09;代码示例&#xff08;异步&#…

解决 :VS code右键没有go to definition选项(转到定义选项)

问题背景&#xff1a; VScode 右键没有“go to definition”选项了&#xff0c;情况如图所示&#xff1a; 问题解决办法&#xff1a; 第一步&#xff1a;先检查没有先安装C/C插件&#xff0c;没有安装就先安装下。 第二步&#xff1a; 打开VS CODE设置界面&#xff1a;文件->…

网络安全的学习与实践经验(附资料合集)

学习资源 在线学习平台&#xff1a; Hack This Site&#xff1a;提供从初学者到高级难度的挑战任务&#xff0c;适合练习各种网络安全技术。XCTF_OJ&#xff1a;由XCTF组委会开发的免费在线网络安全网站&#xff0c;提供丰富的培训材料和资源。SecurityTube&#xff1a;提供丰…

《Rust权威指南》学习笔记(五)

高级特性 1.在Rust中&#xff0c;unsafe是一种允许绕过Rust的安全性保证的机制&#xff0c;用于执行一些Rust默认情况下不允许的操作。unsafe存在的原因是&#xff1a;unsafe 允许执行某些可能被 Rust 的安全性检查阻止的操作&#xff0c;从而可以进行性能优化&#xff0c;如手…

使用R语言绘制标准的中国地图和世界地图

在日常的学习和生活中&#xff0c;有时我们常常需要制作带有国界线的地图。这个时候绘制标准的国家地图就显得很重要。目前国家标准地图服务系统向全社会公布的标准中国地图数据&#xff0c;是最权威的地图数据。 今天介绍的R包“ggmapcn”&#xff0c;就是基于最新公布的地图…

Flutter踩坑记-第三方SDK不兼容Gradle 8.0,需适配namespace

最近需要集成Flutter作为Module&#xff0c;Flutter依赖了第三方库&#xff0c;Gradle是8.0版本。 编译报错&#xff1a; 解决办法是在.android根目录下的build.gradle下新增一行代码&#xff1a; buildscript {ext.kotlin_version "1.8.22"repositories {google()…

golang 编程规范 - 项目目录结构

原文&#xff1a;https://makeoptim.com/golang/standards/project-layout 目录结构 Go 目录 cmdinternalpkgvendor 服务端应用程序目录 api Web 应用程序目录 web 通用应用程序目录 buildconfigsdeploymentsinitscriptstest 其他目录 assetsdocsexamplesgithooksthird_par…

蓝桥杯备赛:C++基础,顺序表和vector(STL)

目录 一.C基础 1.第一个C程序&#xff1a; 2.头文件&#xff1a; 3.cin和cout初识&#xff1a; 4.命名空间&#xff1a; 二.顺序表和vector&#xff08;STL&#xff09; 1.顺序表的基本操作&#xff1a; 2.封装静态顺序表&#xff1a; 3.动态顺序表--vector&#xff1a;…

node.js之---事件循环机制

事件循环机制 Node.js 事件循环机制&#xff08;Event Loop&#xff09;是其核心特性之一&#xff0c;它使得 Node.js 能够高效地处理大量并发的 I/O 操作。Node.js 基于 非阻塞 I/O&#xff0c;使用事件驱动的模型来实现异步编程。事件循环是 Node.js 实现异步编程的基础&…

如何在 Ubuntu 22.04 上部署 Nginx 并优化以应对高流量网站教程

简介 本教程将教你如何优化 Nginx&#xff0c;使其能够高效地处理高流量网站。 Nginx 是一个强大且高性能的 Web 服务器&#xff0c;以其高效处理大量并发连接的能力而闻名&#xff0c;这使得它成为高流量网站的流行选择。 正确优化 Nginx 可以显著提高服务器的性能&#xff0…