C++学习笔记(十四)——分区存储

发布于:2025-03-07 ⋅ 阅读:(79) ⋅ 点赞:(0)

一、 分区存储

分区存储的作用:
程序运行时内存的不同区域,不同的数据类型会存储在不同的存储区。

C++ 的内存通常分为以下四个区域:

存储区 描述 示例
代码区(Code Segment) 存储 程序的可执行代码,通常是只读的 函数代码
全局/静态区(Data Segment) 存储 全局变量、静态变量、常量,程序运行结束时释放 static 变量、全局变量
栈区(Stack Segment) 存储 局部变量、函数参数、返回地址后进先出(LIFO) 方式管理 局部变量、函数调用
堆区(Heap Segment) 通过 new/malloc 动态分配的内存,需要手动释放 new 分配的对象

C++ 内存分区示意图:

+---------------------+
|  代码区(Code)    |  存储函数代码
+---------------------+
|  全局/静态区(Data)|  存储全局变量 & 静态变量
+---------------------+
|  堆区(Heap)      |  动态分配的对象,需手动释放
+---------------------+
|  栈区(Stack)     |  存储局部变量 & 函数参数
+---------------------+

二、代码区(Code Segment)

作用:
存储 程序的机器代码(可执行指令),通常是只读的,防止修改代码本身。

存储内容如下

  • 函数的代码(包括 main() 和用户自定义函数)。
  • 只读的常量数据(某些编译器优化可能放到常量区)。

示例:

#include <iostream>
using namespace std;

void func() 
{
    cout << "Hello, Code Segment!" << endl;
}

int main() {
    func();

    system("pause");
    return 0;
}

注意

  • func()函数代码存储在代码区,不可修改。

三、 全局/静态区(Data Segment)

作用:

  • 存储全局变量、静态变量、常量,程序启动时分配,程序结束时释放。
  • 数据生命周期贯穿整个程序,不会被自动销毁。

示例:

#include <iostream>
using namespace std;

// 全局变量
int globalVar = 100;

void demo() 
{
    // 静态变量
    static int staticVar = 50;
    cout << "staticVar = " << staticVar << endl;
    staticVar++;
}

int main() {
    cout << "globalVar = " << globalVar << endl;
    demo();
    demo();  // 静态变量的值不会丢失
    

    system("pause");
    return 0;
}

注意

  • globalVar 存储在全局区,整个程序可访问。
  • staticVar 存储在静态区,函数 demo() 多次调用不会重新初始化(静态变量只能初始化一次)。

四、 栈区(Stack Segment)

作用:

  • 存储局部变量、函数参数、返回地址,由编译器自动管理
  • 采用 后进先出(LIFO) 方式:
    • 函数调用时,为局部变量和参数分配内存。
    • 函数返回时,释放该函数的栈内存。
  • 占用内存小,但管理效率高

示例:

#include <iostream>
using namespace std;

void stackDemo(int n) 
{
    int localVar = n;
    cout << "局部变量 localVar = " << localVar << endl;
}

int main() {
    stackDemo(10);

    system("pause");
    return 0;
}

注意

  • localVar局部变量,存储在栈区
  • 函数结束后,局部变量会被自动释放

栈区问题:

  • 栈溢出(Stack Overflow):递归调用过深会导致栈溢出。
  • 局部变量作用域有限:超出作用域后自动释放。

五、 堆区(Heap Segment)

作用:

  • 通过 newmalloc 动态分配内存,手动释放。
  • 灵活管理内存,适用于大对象或运行时不确定的数据。
  • 需要 deletefree() 释放内存,否则会导致内存泄漏

示例:

#include <iostream>
using namespace std;

int main() {
    int* p = new int(10);  // 在堆区分配一个 int
    cout << "堆区变量的值: " << *p << endl;

    delete p;  // 释放内存

    system("pause");
    return 0;
}

*注意

  • new int(10) 在堆区分配一个 int 变量(其值为10),返回指针 p
  • 使用 delete 释放内存,否则会导致内存泄漏

六、内存分配与释放

(1) malloc/free vs new/delete

操作 C 语言 (malloc/free) C++ (new/delete)
分配 malloc(size) new Type
释放 free(ptr) delete ptr
是否调用构造函数
返回类型 void*(需转换) 直接返回正确类型
适用范围 C 语言、C++ C++

示例:

#include <iostream>
using namespace std;

int main() {
    // 1、使用 new/delete
    int* p1 = new int(10);  // 分配一个 int
    cout << "*p1 = " << *p1 << endl;
    delete p1;  // 释放

    // 2、使用 malloc/free
    int* p2 = (int*)malloc(sizeof(int));  // 分配内存
    *p2 = 10;
    cout << "*p2 = " << *p2 << endl;
    free(p2);  // 释放

    system("pause");
    return 0;
}

注意:
推荐在 C++ 中使用 new/delete,因为:

  • 支持对象的构造与析构
  • 无需手动转换类型

(2) 内存泄漏与 delete

描述:
内存泄漏:未释放堆区内存,导致程序占用内存不断增长。

示例——内存泄漏:

#include <iostream>
using namespace std;

void leak() 
{
    int* p = new int(100);  // 动态分配
    // 错误 没有 delete,导致内存泄漏
}

int main() {
    leak();

    system("pause");
    return 0;
}

示例——解决方法:

#include <iostream>
using namespace std;

void noLeak()
{
    int* p = new int(100);
    delete p;  // 释放内存
}

int main() {
    noLeak();

    system("pause");
    return 0;
}