C/C++ 基础笔记(六)
2026/6/12 11:37:02 网站建设 项目流程

核心知识:程序内存五大分区、各分区特性、变量生命周期、动态内存管理、void 指针、C/C++ 动态内存差异、二维数组模拟、内存风险与扩容


一、程序内存五大分区(核心)

概念

程序运行时内存划分为 5 个功能区,负责存储不同类型数据,管理方式、生命周期各不相同。

特性

  1. 代码区:存储编译后的程序指令,只读,程序全程存在。

  2. 常量区:存储字符串常量、const 常量、数字字面量;只读不可修改,程序全程存在。

  3. 栈区(Stack):存储普通局部变量、函数参数、临时变量;自动分配、自动释放(函数 / 大括号结束),作用域仅限当前范围,生命周期短。

  4. 静态全局区(静态区):存储全局变量、static 全局变量、static 局部变量;程序全程存在,默认初始化为 0,static 局部变量仅初始化一次、值保留。

  5. 堆区(Heap):存储手动申请的动态内存;手动申请、手动释放,生命周期由程序员控制,一次性申请内存连续、多次申请不连续。

代码示例

// 全局变量(静态区) int g_num; // 静态全局变量(静态区) static int sg_num; ​ void fun() { // 局部变量(栈区) int a = 10; // 静态局部变量(静态区),仅初始化一次 static int sl_num = 0; // 动态内存(堆区) int* p = new int; }

相似概念比较:栈区 vs 堆区

  • 栈区:自动管理、速度快、空间小、生命周期短。

  • 堆区:手动管理、速度慢、空间大、生命周期可控。


二、变量作用域与生命周期

概念

作用域指变量有效访问范围,生命周期指变量占用内存的时长,随内存分区不同而不同。

特性

  1. 局部变量(栈区):作用域从定义到当前函数 / 大括号结束;生命周期同作用域,结束即释放,未初始化值为随机垃圾值。

  2. 全局变量(静态区):作用域整个程序;生命周期程序启动到结束,默认初始化为 0。

  3. 静态局部变量(静态区):作用域仅限定义的函数内;生命周期程序全程,仅初始化一次,值保留。

  4. 动态变量(堆区):无固定作用域,通过指针访问;生命周期从申请到释放,不释放则永久占用。

代码示例

void test() { // 栈区变量:作用域仅限test函数 int i = 0; // 静态局部变量:函数结束不释放,下次调用值保留 static int cnt = 0; cnt++; cout << cnt << endl; // 多次调用依次输出1、2、3... }

三、动态内存管理(堆区)

概念

通过 C/C++ 专用函数 / 运算符手动申请、释放堆内存,灵活控制内存使用。同一次申请的内存是连续的,不同次不一定。

特性

1. C 语言:malloc/calloc/realloc/free
  • 头文件:<stdlib.h>

  • malloc(字节数):申请指定字节内存,不初始化,返回void*(需强转)。

  • calloc(个数, 单字节数):申请 “个数 × 字节数” 内存,自动初始化为 0

  • realloc(旧指针, 新字节数):扩容 / 缩容内存,数据保留,扩容后地址可能变更。

  • free(指针):释放堆内存,释放后指针置空(防野指针)。

2. C++:new/new[]/delete/delete[]
  • new 类型:申请单个对象,返回对应类型指针。

  • new 类型[n]:申请 n 个对象数组。

  • delete 指针:释放单个对象。

  • delete[] 指针:释放数组(必须加 [],否则释放不全)。

3. C vs C++ 动态内存差异
  • C:按字节申请,返回void*,需手动强转。例如需要10个int型的数组内存,直接分配40个字节内存。

  • C++:按类型申请,自动计算大小,无需强转,语法更安全。例如需要10个int型的数组内存,直接分配10个int型内存。

代码示例

// C语言动态内存 #include <stdlib.h> //calloc(个数,单个的字节数) int* p1 = (int*)calloc(10,sizeof(int)); p1[0]; free(p1); p1 = NULL; //malloc(总字节数) int* p2 = (int*)malloc(10*sizeof(int)); p1[2]; free(p2); p2 = NULL; //realloc(起点,追加字节数) ​ ​ // C++动态内存 int* p3 = new int; *p3 = 0; delete p3; p3 = nullptr; ​ int *p4 = new int(0); cout<<*p2<<endl; delete p4; p4 = nullptr; ​ int *p5 = new int[5]; p5[3]; delete p5;//错误写法,只释放第一个位置 delete[] p5;//自动释放全部 p5 = nullptr; ​ // arr[2][3] int **pArr = new int*[7]; for(int i=0;i<7;i++){ pArr[i] = new int[9]; } pArr[3][4];

四、void 指针(C 语言核心)

概念

无类型指针,可接收任意类型指针,但其他类型的指针不能接收void*,用于通用内存地址传递。

特性

  1. 可指向任意类型数据,不能解引用(*p)不能指针偏移(无类型大小)。

  2. 不能定义变量(无内存大小)。

  3. 用途:malloc/calloc/realloc 返回值类型,需强转为具体类型后使用。

代码示例

void* p = malloc(4); // *p = 10; // 错误:不能解引用 int* int_p = (int*)p; // 强转后使用 *int_p = 10;

五、二级指针模拟二维数组(堆区)

概念

通过一级指针数组 + 堆内存,灵活模拟二维数组,支持动态调整大小。

特性

  1. 原理:int** p指向指针数组,每个元素(p[i])指向一维数组。

  2. 内存特点:每行连续、行与行不连续。

  3. 释放顺序:先释放每行数组,再释放指针数组。

代码示例

// C++模拟7行9列二维数组 int** p = new int*[7]; // 申请7行指针数组 for (int i = 0; i < 7; i++) { p[i] = new int[9]; // 每行申请9列 } // 访问元素 p[0][1] = 10; // 释放内存(倒序) for (int i = 0; i < 7; i++) { delete[] p[i]; } delete[] p; p = NULL;

六、动态内存风险(必考)

概念

堆内存手动管理易引发严重问题,需严格规避。

特性

  1. 内存泄漏:申请内存后不释放,内存永久占用,导致程序卡顿、崩溃、系统性能下降。

  2. 野指针:释放内存后仍通过原指针访问,或指针未初始化,引发非法内存访问,程序崩溃。

  3. 规避方法:申请必释放、释放后置空、不越界访问。

代码示例

// 内存泄漏示例 void leak() { int* p = new int; // 忘记释放,内存永久占用 } ​ // 野指针示例 int* p = new int; delete p; *p = 10; // 错误:野指针访问,程序崩溃

七、动态扩容

概念

堆内存不足时,重新申请更大内存、复制旧数据、释放旧内存,实现数组动态增长。

特性

  1. 步骤:初始申请→满时扩容(如每次 + 5)→申请新内存→复制旧数据→释放旧内存→更新指针。

  2. 应用:动态数组、可变长度数据存储。

代码示例

int cap = 5; // 初始容量 int* arr = new int[cap]; int cnt = 0; // 数据个数 ​ // 数据满时扩容 if (cnt >= cap) { cap += 5; // 扩容+5 int* new_arr = new int[cap]; // 复制旧数据 for (int i = 0; i < cnt; i++) { new_arr[i] = arr[i]; } delete[] arr; // 释放旧内存 arr = new_arr; // 更新指针 }

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询