【一天一个计算机知识】—— 【 C/C++ 内存管理与分布】

【一天一个计算机知识】—— 【 C/C++ 内存管理与分布】



⚡ CYBER_PROFILE ⚡
/// SYSTEM READY ///


[WARNING]: DETECTING HIGH ENERGY

🌊 🌉 🌊 心手合一 · 水到渠成

分隔符
>>> ACCESS TERMINAL <<<
[ 🦾 作者主页 ][ 🔥 C语言核心 ]
[ 💾 编程百度 ][ 📡 代码仓库 ]

---------------------------------------
Running Process: 100% | Latency: 0ms


索引与导读

🚩一、C/C++ 内存分布

我们先来看下面的一段代码和相关问题:

#include<stdio.h>#include<stdlib.h>// 【全局/静态区】.data:已初始化的全局变量int globalVar =1;// 【全局/静态区】.data:已初始化的静态全局变量(作用域限制在本文件)staticint staticGlobalVar =1;voidTest(){// 【全局/静态区】.data:已初始化的静态局部变量(生命周期为整个程序)staticint staticVar =1;// 【栈区】:局部变量,函数运行结束自动释放int localVar =1;// 【栈区】:局部数组int num1[10]={1,2,3,4};// 【栈区】:字符数组(注意:"abcd" 会被拷贝到栈上)char char2[]="abcd";// 【指针在栈区】,但指向的 "abcd" 字符串字面量在【常量区/代码段】constchar* pChar3 ="abcd";// 【指针在栈区】,指向【堆区】通过 malloc 分配的内存int* ptr1 =(int*)malloc(sizeof(int)*4);// 【指针在栈区】,指向【堆区】通过 calloc 分配并初始化的内存int* ptr2 =(int*)calloc(4,sizeof(int));// 【指针在栈区】,将 ptr2 原有的【堆区】内存进行扩充/移动int* ptr3 =(int*)realloc(ptr2,sizeof(int)*4);// 手动释放【堆区】内存free(ptr1);free(ptr3);}
在这里插入图片描述

在这里插入图片描述

🚩二、C语言的动态内存管理

🔗Lucy的空间骇客裂缝:C语言动态内存管理

💪C动态内存管理的面试考点

1)realloc的工作机制

voidTest(){int* p2 =(int*)calloc(4,sizeof(int));int* p3 =(int*)realloc(p2,sizeof(int)*10);free(p3 );}
  • 这里需要free(p2)
  • 不需要。 甚至绝对不能这样做
原因在于 realloc 的工作机制:如果 realloc 成功扩容,它会返回一个新的内存地址(可能是原地址,也可能是搬迁后的新地址)。如果返回了新地址,原内存块(p2)会自动被释放。如果你手动执行 free(p2),会导致“重复释放”(Double Free)的错误,这通常会引起程序崩溃

2)malloc/calloc/realloc的区别是什么?

函数功能描述初始化行为参数形式
malloc分配指定字节大小的内存。不初始化。内存里是随机的垃圾值。malloc(size_t size)
calloc分配 n 个元素的内存,并清零。自动初始化为 0calloc(n, size)
realloc调整已分配内存块的大小。不对新增空间进行初始化。realloc(ptr, new_size)

🚩三、C++ 动态内存管理

  • C语言内存管理方式在C++中可以继续使用
  • C++又提出了自己的内存管理方式:通过newdelete操作符进行动态内存管理

1)操作内置类型

C++中,内置类型(如 int, double, char 等)的动态内存分配主要通过 newdelete 运算符来实现

1.1)单个变量的分配和释放

  • 分配:new 类型 或 new 类型(初始值)
  • 释放:delete 指针变量
intmain(){// 1. 分配一个未初始化的 intint* p1 =newint;// 2. 分配并初始化为 100int* p2 =newint(100);// 使用完毕后必须释放内存delete p1;delete p2;// 良好的习惯:将指针置为空,防止野指针 p1 =nullptr; p2 =nullptr;return0;}

1.2)一维数组的分配与释放

处理数组时,需要使用方括号 []

  • 分配:new 类型[元素个数]
  • 释放:delete[] 指针变量 (注意:释放数组必须加 [],否则会导致未定义行为或内存泄漏)
voidmanageArray(){int size =5;// 分配一个长度为 5 的 int 数组int* arr =newint[size];// 初始化数组(C++11 之后也可以使用 new int[5]{1, 2, 3, 4, 5})for(int i =0; i < size;++i){ arr[i]= i *10;}// 释放数组内存delete[] arr;}

2)操作自定义类型

对于自定义类型(如 structclass),C++newdelete 不仅仅是分配内存,它们还负责调用构造函数和析构函数

  • 最核心的差异在于:自定义类型的生命周期管理包含了初始化(调用构造函数)清理(调用析构函数) 的过程
#include<iostream>usingnamespace std;classA{public:A(int a =0):_a(a){ cout <<"A():"<<this<< endl;}~A(){ cout <<"~A():"<<this<< endl;}private:int _a;};intmain(){ A* p1 =(A*)operatornew(sizeof(A)); A* p2 =newA(1);operatordelete(p1);delete p2;int* p3 =(int*)operatornew(sizeof(int));int* p4 =newint;operatordelete(p3);delete p4; A* p5 =(A*)operatornew(sizeof(A)*10); A* p6 =new A[10];operatordelete[](p5);delete[] p6;return0;}

3)operator new与operator delete函数

  • newdelete 是用户进行动态内存申请和释放的操作符,operator newoperator delete 是系统提供的全局函数
  • new 在底层调用 operator new 全局函数来申请空间,delete 在底层通过 operator delete 全局函数来释放空间

  • new 表达式 (new expression): 这是我们在代码中常用的 Type* p = new Type();。它是一个“全自动”过程,做了两件事:
    1. 调用 operator new 分配原始内存。
    2. 调用构造函数初始化对象。
  • operator new (函数): 这是一个类似于 malloc 的函数,它的唯一任务是分配一块指定大小的原始内存,不负责构造对象。

3.1)operator new详解

🔗Lucy的空间骇客裂缝:operator new官方解析
  • 原型:
void*operatornew(size_t size);
  • 工作原理
    • 参数: size 是需要分配的字节数(编译器会自动计算对象大小并传入)。
    • 返回值: 返回指向分配的内存起始地址的 void* 指针。
    • 失败处理: 默认情况下,如果分配失败,它不会返回 nullptr,而是抛出 std::bad_alloc 异常。
    • 自定义行为: 你可以重载全局或类特定的 operator new 来实现自己的内存池或审计逻辑

3.2)operator delete 详解

🔗Lucy的空间骇客裂缝:operator delete官方解析
  • 原型:
voidoperatordelete(void* ptr)noexcept;
  • 工作原理
    • 对应关系delete 表达式会先调用对象的析构函数,然后调用 operator delete 来释放内存。
    • 安全性:根据 C++ 标准,向 operator delete 传递 nullptr 是安全的,函数会直接返回而不执行任何操作。
    • 释放逻辑:在底层,它通常封装了 free() 或者系统底层的内存回收接口。
C++ 中,noexcept 是一个异常说明,它告诉编译器和程序员:这个函数保证不会抛出异常

通过上述两个全局函数的实现知道,operator new 实际也是通过 malloc 来申请空间,如果 malloc 申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过 free 来释放空间的


4)new和delete的实现原理

4.1)内置类型

如果申请的是内置类型的空间,newmallocdeletefree 基本类似,不同的地方是:
new/delete 申请和释放的是单个元素的空间,new[]delete[] 申请的是连续空间,而且 new 在申请空间失败时会抛异常,malloc 会返回 NULL


4.2)自定义类型

  • new 的原理
    1. 调用 operator new 函数申请空间
    2. 在申请的空间上执行构造函数,完成对象的构造
  • delete 的原理
    1. 在空间上执行析构函数,完成对象中资源的清理工作
    2. 调用 operator delete 函数释放对象的空间
  • new T[N] 的原理
    1. 调用 operator new[] 函数,在 operator new[] 中实际调用 operator new 函数完成 N 个对象空间的申请
    2. 在申请的空间上执行 N 次构造函数
  • delete[] 的原理
    1. 在释放的对象空间上执行 N 次析构函数,完成 N 个对象中资源的清理
    2. 调用 operator delete[] 释放空间,实际在 operator delete[] 中调用 operator delete 来释放空间

5)malloc/free和new/delete的区别

malloc/freenew/delete 的共同点是:都是从堆上申请空间,并且需要用户手动释放。不同的地方是:

  1. mallocfree 是函数,newdelete 是操作符
  2. malloc 申请的空间不会初始化,new 可以初始化
  3. malloc 申请空间时,需要手动计算空间大小并传递,new 只需在其后跟上空间的类型即可,如果是多个对象,[] 中指定对象个数即可
  4. malloc 的返回值为 void*,在使用时必须强转,new 不需要,因为 new 后跟的是空间的类型
  5. malloc 申请空间失败时,返回的是 NULL,因此使用时必须判空,new 不需要,但是 new 需要捕获异常
  6. 申请自定义类型对象时,malloc/free 只会开辟空间,不会调用构造函数与析构函数,而 new 在申请空间后会调用构造函数完成对象的初始化,delete 在释放空间前会调用析构函数完成空间中资源的清理释放

💻结尾— 核心连接协议

警告:🌠🌠正在接入底层技术矩阵。如果你已成功破解学习中的逻辑断层,请执行以下指令序列以同步数据:🌠🌠


【📡】 建立深度链接:关注本终端。在赛博丛林中深耕底层架构,从原始代码到进阶协议,同步见证每一次系统升级。

【⚡】 能量过载分发:执行点赞操作。通过高带宽分发,让优质模组在信息流中高亮显示,赋予知识跨维度的传播力。

【💾】 离线缓存核心:将本页加入收藏。把这些高频实战逻辑存入你的离线存储器,在遭遇系统崩溃或需要离线检索时,实现瞬时读取。

【💬】 协议加密解密:评论区留下你的散列码。分享你曾遭遇的代码冲突或系统漏洞(那些年踩过的坑),通过交互式编译共同绕过技术陷阱。

【🛰️】 信号频率投票:通过投票发射你的选择。你的每一次点击都在重新定义矩阵的进化方向,决定下一个被全量拆解的技术节点。


在这里插入图片描述

Read more

Vue3 本地环境 Vite 与生产环境 Nginx 反向代理配置方法汇总【反向代理篇】

Vue3 本地环境 Vite 与生产环境 Nginx 反向代理配置方法汇总【反向代理篇】

文章目录 * 一、前言 * 二、问题场景 * 三、开发环境配置(Vite) * 四、生产环境配置(Nginx) * 4.1 初始错误配置 * 4.2 正确配置方案 * 4.3 配置解析 * 4.4高级配置选项 * 五、常见问题排查 * 六、开发环境 vs 生产环境对比 * 七、总结 一、前言 在前后端分离架构中,前端访问后端资源(尤其是图片、文件等静态资源)的反向代理配置是一个常见且容易踩坑的问题。最近在开发一个 Vue3 + .NET8 的项目时,我就遇到了开发环境配置正常,但部署到生产环境后图片无法访问的问题。本文将详细记录这个问题的解决过程,并给出开发环境和生产环境的完整代理配置方案。 二、问题场景 * 前端:Vue3 项目,

By Ne0inhk
不用服务器也能让本地 Websocket 跑遍全网?cpolar帮我搞定了

不用服务器也能让本地 Websocket 跑遍全网?cpolar帮我搞定了

文章目录 * 前言 * 1. Java 服务端demo环境 * 2. 在pom文件引入第三包封装的netty框架maven坐标 * 3. 创建服务端,以接口模式调用,方便外部调用 * 4. 启动服务,出现以下信息表示启动成功,暴露端口默认9999 * 5. 创建隧道映射内网端口 * 6. 查看状态->在线隧道,复制所创建隧道的公网地址加端口号 * 7. 以基于go的socket客户端为例,通过公网连接java socket服务端 * 8. 通过git下载websocket框架 * 9. 创建客户端, 注意:Host值为上面复制的隧道公网地址!! * 10. 接着启动服务,与服务端连接,出现服务端返回的字样表示连接成功 * 11. 客户端在控制台输入信息,回车 * 12. 服务端出现客户端发送的信息 * 13. 服务端控制台输入消息,回车 * 14. 客户端收到服务端回复的消息,连接成功 * **总之,cpolar 让本地

By Ne0inhk
【Linux网络系列】:网络+网络编程(UDPsocket+TCPsocket)

【Linux网络系列】:网络+网络编程(UDPsocket+TCPsocket)

🔥 本文专栏:Linux网络 🌸作者主页:努力努力再努力wz 💪 今日博客励志语录: 我们常苦苦寻找那个“正确”的选择,但或许,比选择更重要的是:鼓起勇气,让自己成为那个“使选择变正确”的人。 引入 在结束了Linux系统部分的学习之后,我们主要掌握了Linux的基本指令、进程与信号、进程间通信、线程等内容。通过这部分内容我们可以发现,它们主要围绕同一台设备上的一个或者多个进程展开。然而在当前的互联网时代,每一台计算机或设备都不是孤立存在的。正如人类具有社会属性,无法完全与世隔绝,当我们步入社会,必然需要与他人接触、建立联系、形成社交网络一样,计算机也需要与其他计算机进行通信,即数据交换。因此,计算机也不是一座“社交孤岛”。 由于计算机之间的通信涉及不同设备,要实现这种跨设备通信,就离不开我们今天要讨论的主题—— 网络 。在本篇博客中,我将从两个方面展开:首先带领大家认识 网络 ,并补充必要的 网络 基础知识;在具备一定基础后,我们将进一步学习 网络编程的相关内容。从本文开始,

By Ne0inhk
I.MX6U 开发板网络环境搭建----(电脑 WiFi 上网,开发板和电脑直连)--虚拟机双网口实现-- Ubuntu20.04

I.MX6U 开发板网络环境搭建----(电脑 WiFi 上网,开发板和电脑直连)--虚拟机双网口实现-- Ubuntu20.04

🎬 渡水无言:个人主页渡水无言 ❄专栏传送门:linux专栏 ⭐️流水不争先,争的是滔滔不绝  📚博主简介:第二十届中国研究生电子设计竞赛全国二等奖 |国家奖学金 | 省级三好学生 | 省级优秀毕业生获得者 | ZEEKLOG新星杯TOP18 | 半导纵横专栏博主 | 211在读研究生 在这里主要分享自己学习的linux嵌入式领域知识;有分享错误或者不足的地方欢迎大佬指导,也欢迎各位大佬互相三连 目录 前言 一、使用场景 二、VMware 设置 三、Ubuntu 设置 3.1设置ens37网络(即NAT 模式的网络适配器) 3.2、测试ubuntu上网功能 3.3、测试ubuntu和Windows互传功能 3.4设置桥接模式的网络适配器 1 的 IP 信息 3.5关闭防火墙 四、windows设置 五、开发板设置并ping测试 5.

By Ne0inhk