C/C++ 基础笔记(六)

核心知识:程序内存五大分区、各分区特性、变量生命周期、动态内存管理、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; // 更新指针
}
相关推荐
秋田君1 小时前
2026 前端新出路:掌握 C++ 核心语法,无缝衔接 QT 桌面开发
前端·c++·qt
handler011 小时前
【C++11 】Lambda 表达式、std::function 与 std::bind 解析
c++·c·c++11·bind·解耦·function·lamda
SoftLipaRZC1 小时前
C语言自定义类型:结构体完全指南
c语言·开发语言
字节高级特工2 小时前
C++11(二) 革新:引用折叠与lambda表达式
java·开发语言·c++·算法
白驹笙鸣2 小时前
STL allocator作用
开发语言·c++
小小编程路2 小时前
C++ STL 原理与性能
开发语言·c++
社交怪人2 小时前
【适合晨练】信息学奥赛一本通C语言解法(题号2054)
c语言
小欣加油2 小时前
leetcode239 滑动窗口最大值
数据结构·c++·算法·leetcode·哈希算法
玖釉-2 小时前
Vulkan 示例解析:pipelines.cpp 如何在一个 Render Pass 中切换多条 Graphics Pipeline
c++·windows·算法·图形渲染