【C/C++】理解 C/C++ 中的堆、栈、静态区和只读区(重传)

我很久以前写过大量的博文都被我删除了,找了一些有价值的重传一下

在 C/C++ 编程中,内存管理是一个重要的基础知识。但国内的大多数初学者是接触不到这些内容的,本文就简单讲解一下,程序编译运行后,代码都被划分成那些区域,再通过运行时程序控制运行的。


一、内存分区简介

C/C++ 程序的内存通常分为以下几个部分:

  1. 栈区(Stack)
    栈区用于存储函数调用时的临时变量(如局部变量、函数参数等)。它由操作系统自动管理,分配和释放内存,速度快,但空间有限。

  2. 堆区(Heap)
    堆区是程序运行中动态分配内存的区域,通常由程序员通过 mallocnew 分配内存,并需要用 freedelete 手动释放。

  3. 静态区(Static Segment)
    静态区存储程序中的全局变量、静态变量和常量。它们在程序运行期间分配一次,直到程序结束时才释放。

  4. 只读区(Read-Only Segment)
    只读区存放不可修改的常量数据(如字符串字面量)。尝试修改只读区的数据会导致程序崩溃。

  5. 代码区(Code Segment)
    代码区存储程序的可执行指令,通常是只读的,防止代码被意外修改。


二、栈区

1. 栈区的特点

  • 自动管理:栈区由操作系统自动分配和释放,程序员无需干预。
  • 存储内容:存储局部变量、函数参数、返回地址等。
  • 生命周期:变量在函数调用时分配,函数结束时自动销毁。
  • 效率高:栈区由于连续的内存分配和自动管理,访问速度非常快。

2. 栈区的示例代码

#include <iostream>

void exampleFunction() {
    int a = 10;  // 局部变量,存储在栈区
    int b = 20;  // 局部变量
    std::cout << "a + b = " << (a + b) << std::endl;
}

int main() {
    exampleFunction();
    return 0;
}

在上面的代码中,ab 是局部变量,存在栈区。当 exampleFunction 执行完毕后,ab 的内存会被自动释放。

3. 开发中的注意事项

  • 栈溢出(Stack Overflow):栈空间有限(通常为几 MB),如果递归深度过大或局部变量占用内存过多,可能会导致栈溢出。
  • 禁止返回栈内存地址:函数结束后,栈上的变量会被销毁,因此返回它们的地址是危险的。
int* riskyFunction() {
    int a = 10;
    return &a;  // 错误!返回已释放的栈内存地址
}

三、堆区

1. 堆区的特点

  • 手动管理:程序员需要通过 mallocnew 分配内存,并使用 freedelete 释放内存。
  • 存储内容:动态分配的内存,例如对象、数组等。
  • 生命周期:由程序员控制,手动释放前内存会一直占用。
  • 灵活性:堆内存可以在程序运行时动态调整大小。

2. 堆区的示例代码

#include <iostream>

int main() {
    int* p = new int(42);  // 在堆区分配一个整数,值为 42
    std::cout << "Value: " << *p << std::endl;
    delete p;  // 手动释放内存
    return 0;
}

3. 开发中的注意事项

  • 及时释放内存:忘记释放堆内存会导致内存泄漏,特别是在长时间运行的程序中。
  • 避免悬空指针:释放堆内存后,指针仍然指向已释放的地址。建议将指针置为 nullptr
int* p = new int(10);
delete p;
p = nullptr;  // 避免悬空指针

四、静态区

1. 静态区的特点

  • 全局变量和静态变量存储在静态区。
  • 生命周期长:变量从程序开始到程序结束始终存在。
  • 默认初始化:未显式初始化的全局变量和静态变量会被自动置为零值。

2. 静态区的示例代码

#include <iostream>

int globalVar = 100;  // 全局变量,存储在静态区

void staticExample() {
    static int staticVar = 10;  // 静态局部变量,存储在静态区
    staticVar++;
    std::cout << "staticVar = " << staticVar << std::endl;
}

int main() {
    staticExample();
    staticExample();  // 再次调用时,staticVar 保留上次的值
    return 0;
}

五、只读区

1. 只读区的特点

  • 存储不可修改的数据:包括字符串字面量和 const 修饰的全局变量。
  • 只读属性:尝试修改只读区的数据会导致运行时崩溃。

2. 示例代码

#include <iostream>

int main() {
    const char* str = "Hello, World!";  // 字符串字面量,存储在只读区
    // str[0] = 'h';  // 错误!尝试修改只读区内容
    std::cout << str << std::endl;
    return 0;
}

六、堆栈区与操作系统堆栈区的关系

1. 操作系统堆栈区是什么?

  • 操作系统为每个线程分配了一块栈内存,称为线程栈系统栈
  • 在 C/C++ 中,程序的栈区就位于操作系统分配的线程栈中。

2. 关系与区别

  • 线程栈是栈区的底层实现:C/C++ 的栈区实际上是操作系统分配的线程栈的一部分。
  • 操作受限:程序员无法直接操作操作系统的线程栈,栈区的内存分配完全由编译器和操作系统管理。

七、内存区域的对比表

特性 栈区 堆区 静态区 只读区
管理方式 系统自动分配和释放 程序员手动分配和释放 系统自动分配,程序结束释放 系统自动分配,程序结束释放
存储内容 局部变量、函数参数等 动态分配的对象和数组 全局变量、静态变量等 常量数据(如字符串字面量)
生命周期 函数调用期间 程序员控制 程序运行期间始终存在 程序运行期间始终存在
是否可修改 可修改 可修改 可修改 不可修改
速度 快速 相对较慢 快速 快速
空间大小 受限(一般为几 MB) 较大(由系统内存决定) 较大 较小

八、堆栈区与堆栈数据结构是否有关系

注意,堆栈区和堆栈实际上没有直接关系。但栈区的数据结构通常确实是栈,但堆区的数据结构一般都比较复杂,不同语言实现也都不太一样。

九、简单总结

  1. 栈区 是函数调用期间的临时存储区域,速度快但空间有限。
  2. 堆区 提供灵活的内存分配方式,但需要程序员手动管理。
  3. 静态区 用于存储全局变量和静态变量,这些变量贯穿程序的整个生命周期。
  4. 只读区 存放不可修改的常量数据,修改会导致错误。
  5. 栈区和操作系统堆栈区密切相关,栈区是线程栈的一部分,由操作系统和编译器协同管理。

理解这些内存区域的作用和特点,不仅能帮助你写出高效的代码,还能避免常见的 Bug,比如内存泄漏、栈溢出等问题。希望本文对你有所帮助!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,084评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,623评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,450评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,322评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,370评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,274评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,126评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,980评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,414评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,599评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,773评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,470评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,080评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,713评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,852评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,865评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,689评论 2 354

推荐阅读更多精彩内容