C++ 内存分布框架

当编写C++程序时,合理地使用内存分配是非常重要的。以下是一份C++内存分布框架梳理,帮助你更好地理解和管理内存:

先给上一个内存分布图,从上到下,内存地址依次降低。

-------------------------------------------------------
|                      High Address                   |
--------------------------------------------------------
|                      Heap                            |
|                    (动态分配)                         |
|--------------------------------------------------- --|
|                      堆栈                            |
|                    (局部变量、函数参数等)               |
|-----------------------------------------------------|
|                     全局/静态存储区                    |
|                     (全局变量、静态变量)                |
|------------------------------------------------------|
|                     常量存储区                         |
|                    (常量值)                           |
|------------------------------------------------------|
|                     代码区                            |
|                     (执行代码)                        |
-------------------------------------------------------
|                      Low Address                     |
--------------------------------------------------------

栈(Stack):

栈上的内存分配是自动的,由编译器负责管理。
用于存储函数的局部变量函数参数函数调用的返回地址等。
栈的大小通常较小,适合存储相对较小的数据。
避免在栈上分配过大的数据,以免造成栈溢出。

#include <iostream>

// 函数声明
void display(int num);

int main() {
    int x = 5;  // 在栈上声明一个整型变量x,并初始化为5
    int y = 10; // 在栈上声明一个整型变量y,并初始化为10

    display(x); // 调用函数display,将x作为参数传递

    return 0;
}

// 函数定义
void display(int num) {
    // 在函数内部声明一个局部变量num,并将传入的参数值复制给它
    std::cout << "The number is: " << num << std::endl;
}

当程序执行到一个函数时,函数的局部变量和参数被分配在栈上;当函数执行完毕时,栈上的这些变量被销毁。

堆(Heap):

堆上的内存分配需要手动管理,使用new关键字进行分配,使用delete关键字进行释放。
用于存储动态分配的数据,如动态数组对象等。
避免内存泄漏,确保每次分配的内存都能被正确释放。

#include <iostream>

int main() {
    int* ptr = nullptr; // 声明一个指向整型的指针,并初始化为nullptr

    // 在堆上动态分配一个整型数组,包含5个元素
    ptr = new int[5];

    // 使用循环为数组赋值
    for (int i = 0; i < 5; ++i) {
        ptr[i] = i * 2;
    }

    // 打印数组的值
    std::cout << "Array elements: ";
    for (int i = 0; i < 5; ++i) {
        std::cout << ptr[i] << " ";
    }
    std::cout << std::endl;

    // 释放动态分配的内存
    delete[] ptr;
    ptr = nullptr;
    return 0;
}

全局/静态存储区(Global/Static Storage Area):

存储全局变量和静态变量。
全局变量在程序启动时被初始化,并在程序的整个生命周期中都存在。
静态变量也类似,但只在声明它的文件内可见。
避免滥用全局变量,尽量减少全局变量的数量,以免影响程序的可维护性和扩展性。

#include <iostream>

// 全局变量
int globalVar = 10;

// 函数声明
void func();

int main() {
    // 输出全局变量的值
    std::cout << "Global variable: " << globalVar << std::endl;

    // 调用函数
    func();

    // 再次输出全局变量的值
    std::cout << "Global variable after function call: " << globalVar << std::endl;

    return 0;
}

// 函数定义
void func() {
    // 修改全局变量的值
    globalVar = 20;
    std::cout << "Global variable inside function: " << globalVar << std::endl;

    // 静态变量
    static int staticVar = 5;
    staticVar++;
    std::cout << "Static variable inside function: " << staticVar << std::endl;
}

代码运行结果:
Global variable: 10
Global variable inside function: 20
Static variable inside function: 6
Global variable after function call: 20

globalVar 是一个全局变量,它在程序的整个生命周期内存在,并且可以在程序的任何地方访问。
func() 函数中修改了全局变量 globalVar 的值,并且声明了一个静态局部变量 staticVar,它的生命周期与程序的生命周期相同,但作用域仅限于 func() 函数内部。
在 main() 函数中调用了 func() 函数,并输出了修改后的全局变量的值。

常量存储区(Constant Storage Area):

存储程序中的常量值,如字符串常量、全局常量等。
这部分内存在程序启动时就已经分配,并在整个程序的生命周期内都不会被修改。
避免在常量存储区中修改常量值,以免引发未定义的行为。

#include <iostream>

int main() {
    // 字符串常量存储在常量存储区
    const char* str = "Hello, world!";

    // 输出字符串常量
    std::cout << "String constant: " << str << std::endl;

    return 0;
}

这块我经常搞混乱,有时候会把 str 变量的内存分配搞错,主要是带有*, 老是会理解成堆上的内存了,老想着去这个内存需不需要去释放。这个是栈内存,自己释放了哈。大家应该不会搞错,其实堆上内存都是动态的,一般都是new和malloc申请出来的。

在这个示例中:

“Hello, world!” 是一个字符串常量,它存储在常量存储区。
str 是一个指向字符常量的指针,它指向字符串常量 “Hello, world!” 的首地址。
当程序运行时,字符串常量 “Hello, world!” 被存储在常量存储区,而指针 str存储在栈上。输出指针 str 的值将显示字符串常量的内容。

代码区(Code Area):

存储程序的执行代码,包括函数体、指令等。
这部分内存在程序加载时分配,并在程序执行期间不会被修改。
避免在代码区中进行写操作,以免导致程序崩溃或其他严重问题。

#include <iostream>

// 函数声明
void sayHello();

int main() {
    // 调用函数
    sayHello();

    return 0;
}

// 函数定义
void sayHello() {
    std::cout << "Hello, world!" << std::endl;
}

在这个示例中:

sayHello() 函数的定义包含了要执行的指令,这些指令将在程序执行时加载到内存的代码区中。
在 main() 函数中调用了 sayHello() 函数,这会导致程序跳转到代码区中 sayHello() 函数的地址,并执行其中的指令,最终输出 “Hello, world!”。
在编译后的可执行文件中,函数的机器码指令将存储在代码区,等待被执行。

总的来说,希望大家看了后,能对内存分布有个简单的了解,合理地使用内存分配结构可以提高程序的性能和稳定性,同时避免常见的内存相关问题。
在编写C++程序时,应该深入理解每种内存分配结构的特点和使用方式,以及注意内存管理的细节,从而编写出高效、稳定的程序。

  • 50
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
### 回答1: 可以使用以下步骤来实现一个 C 顶层框架: 1. 定义框架的目的和功能,并确定需要哪些模块和功能来支持这些目的。 2. 设计数据结构和模块之间的接口,以便在实现时使用。 3. 实现每个模块,包括分配内存、读写文件、处理数据和其他必要的功能。 4. 测试每个模块的功能,并确保它们能够正常工作。 5. 组装所有模块,并确保它们能够协同工作,以实现预期的功能。 6. 发布框架,并提供文档和支持,以帮助其他开发人员使用该框架。 ### 回答2: 实现一个C语言的顶层框架可以分为几个步骤。首先,我们需要定义程序的入口函数main(),在这个函数里面我们可以声明变量、调用其他函数、进行流程控制等等。 接下来,我们可以将程序需要用到的函数先声明在main()函数之前。这样做可以提前告诉编译器我们将要使用哪些函数,以便编译器能够正确编译整个程序。 例如,我们可以声明一个名为calculation()的函数,用于进行计算操作。在这个函数里面可以定义一些变量,并进行相应的计算。这样做的好处是可以将主要的计算逻辑单独封装在一个函数里面,使得代码清晰易懂,并且方便维护和重用。 在顶层框架中,我们还可以定义其他类型的函数,例如输入输出函数、辅助函数等等,根据实际需求来决定。这些函数的目的是为了提供更全面的功能,并且保持代码的模块化和可读性。 此外,我们还可以在顶层框架中添加注释来解释函数的功能、参数、返回值等信息,以方便其他使用者理解和使用我们的程序。 最后,在main()函数中,我们可以按照需要调用其他函数,完成整个程序的逻辑。 总结起来,实现一个C语言的顶层框架需要定义入口函数main(),声明其他函数并在适当的地方调用它们,以完成程序的逻辑。此外,还可以加入注释、定义变量等来提高代码的可读性和维护性。 ### 回答3: 实现一个C语言的顶层框架需要以下步骤: 1. 定义主函数:首先,在代码中定义一个主函数main()作为程序的入口点。 2. 引入头文件:根据需要,引入所需的C语言标准头文件,如stdio.h等。 3. 定义全局变量:如果需要使用全局变量,可以在主函数之前或其他需要的地方定义变量。 4. 定义函数:根据需求,可以定义各种函数,例如功能函数、处理函数、输入输出函数等。 5. 实现功能逻辑:在主函数或其他定义的函数中,编写程序的逻辑实现代码,包括各种操作、判断、循环等。 6. 处理输入输出:根据需要,通过输入函数(如scanf())获取用户输入的数据,并通过输出函数(如printf())将结果打印出来。 7. 错误处理:针对可能出现的错误情况,使用错误处理机制,如使用条件语句和try-catch机制进行异常处理。 8. 添加注释:为了增强代码的可读性,可以在关键部分添加注释,解释代码的功能、逻辑或注意事项。 9. 编译和运行:将代码保存为以.c为扩展名的源文件,使用C编译器进行编译,生成可执行文件,并运行程序。 总之,实现一个C语言的顶层框架的关键是确定好代码的结构、模块和逻辑,并根据需求完善相关代码,最终通过编译和运行验证代码的正确性和功能实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

碧 波

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值