【5minC++基本功】C++中的内存区域——静态存储区(static extern关键字)|堆区|栈区

【5minC++基本功】C++中的内存区域------静态存储区 static extern关键字|堆区|栈区

    • [1. 静态存储区](#1. 静态存储区)
      • [1.1 静态存储区的数据及其特点](#1.1 静态存储区的数据及其特点)
      • [1.2 代码示例](#1.2 代码示例)
        • [1.2.1 ==全局变量/常量==](#1.2.1 ==全局变量/常量==)
        • [1.2.2 ==静态全局变量==](#1.2.2 ==静态全局变量==)
        • [1.2.3 ==静态成员变量==](#1.2.3 ==静态成员变量==)
        • [1.2.4 ==静态局部变量==](#1.2.4 ==静态局部变量==)
    • [2. 堆区](#2. 堆区)
      • [2.1 堆区特点](#2.1 堆区特点)
      • [2.2 堆区代码示例](#2.2 堆区代码示例)
        • [2.2.1. 通过库函数------std::malloc/std::free](#2.2.1. 通过库函数——std::malloc/std::free)
        • [2.2.2 通过::operator new/delete](#2.2.2 通过::operator new/delete)
    • [3. 栈区](#3. 栈区)
      • [3.1 栈区特点](#3.1 栈区特点)
      • [3.2 栈区代码示例](#3.2 栈区代码示例)
      • [3.3 需要注意的问题](#3.3 需要注意的问题)

C++编写代码讲求高效, 对于程序员来说, 内存资源是非常宝贵的, 内存管理也是编写高效和稳定代码的基础.
在C++中, 内存区域大致可以划分为四种, 分别是代码区、常量区、全局区/静态区、堆区和栈区。

1. 静态存储区

1.1 静态存储区的数据及其特点

静态存储区中, 全局变量特点如下:

  • 生命周期长: 全局变量的生命周期贯穿整个程序的运行期,从程序开始到结束。适用于需要在多个函数之间共享数据的情况。

  • 共享访问: 作用域是整个程序,在定义它们的文件中可以直接访问/修改, 也可以通过extern关键字在其他文件中访问/修改。

  • 初始化: 如果没有显式初始化,全局变量/常量中的数值类型会自动初始化为0,指针类型初始化为nullptr。

static修饰的全局变量作用域和用法略有区别:

  • 作用域: 仅限于定义它的源文件,其他源文件无法通过 extern 声明访问该变量

static修饰的局部变量:

  • 作用域: 与普通的局部变量相同,仅限于声明它们的函数内部。与普通局部变量不同的是,静态局部变量的生命周期跨越了多次函数调用。 如果一个函数需要记住上一次调用时的状态或计数器,静态局部变量是一个很方便的选择。

static修饰的成员变量:

  • 随着类的创建而产生, 属于类而不属于类的任何对象。

1.2 代码示例

1.2.1 全局变量/常量

在a.cpp中定义全局变量/常量

cpp 复制代码
// a.cpp
#include <iostream>

// 定义全局变量
int globalVar = 100;

// 定义全局常量
const int globalConst = 200;

void modifyGlobalVar() {
    globalVar += 50;
}

void printGlobals() {
    std::cout << "Global Variable: " << globalVar << std::endl;
    std::cout << "Global Constant: " << globalConst << std::endl;
}

int main() {
    printGlobals(); // 输出:Global Variable: 100, Global Constant: 200
    modifyGlobalVar();
    printGlobals(); // 输出:Global Variable: 150, Global Constant: 200
    return 0;
}

在b.cpp中访问和修改:

cpp 复制代码
// b.cpp
#include <iostream>

// 声明外部变量和常量
extern int globalVar;
extern const int globalConst;

// 声明外部函数
void modifyGlobalVar();
void printGlobals();

int main() {
    printGlobals(); // 输出:Global Variable: 150, Global Constant: 200
    modifyGlobalVar();
    printGlobals(); // 输出:Global Variable: 200, Global Constant: 200
    return 0;
}
1.2.2 静态全局变量

注意: 只能定义它的源文件访问和修改,其他文件无法通过 extern 声明访问该变量

cpp 复制代码
#include <iostream>

// 静态全局变量的定义
static int globalStaticVar = 100;

void func() {
    // 访问静态全局变量
    std::cout << "Inside func(): globalStaticVar = " << globalStaticVar << std::endl;
}
int main() {
    // 访问静态全局变量
    std::cout << "Inside main(): globalStaticVar = " << globalStaticVar << std::endl;
    // 修改静态全局变量
    globalStaticVar = 200;
    // 调用函数
    func();
    return 0;
}
1.2.3 静态成员变量
cpp 复制代码
class MyClass {
public:
    static void staticFunc() {
        std::cout << "Inside staticFunc()" << std::endl;
    }
};
int main() {
    // 调用静态成员函数
    MyClass::staticFunc();
    // 也可以通过对象调用,但不是推荐的用法
    MyClass obj;
    obj.staticFunc();
    return 0;
}
1.2.4 静态局部变量
cpp 复制代码
#include <iostream>
void func() {
    // 静态局部变量
    static int count = 0;
    count++;
    std::cout << "count: " << count << std::endl;
}
int main() {
    // 调用函数多次
    func(); // 输出:count: 1
    func(); // 输出:count: 2
    func(); // 输出:count: 3
    return 0;
}

2. 堆区

2.1 堆区特点

  • 堆区是一种动态分配和释放的空间, 由程序员手动管理。
  • 堆内存的分配是不连续的, 大小由程序员控制。分配和释放频繁会导致内存碎片问题,可能需要实现内存池或者其他机制来解决。
  • 存储程序运行时动态分配的数据。

2.2 堆区代码示例

有两种形式来调用和释放堆区变量。

2.2.1. 通过库函数------std::malloc/std::free
  • 首先需要包含std::malloc的头文件------ #include <cstdlib>, 其次就是std::malloc的具体使用.
  • std::malloc使用时, 指定需要开辟的字节数,如果内存开辟失败, 会返回一个空指针.
  • 示例如下:
cpp 复制代码
void *buf = std::malloc(16);
if(buf!=nullptr){
	//按需使用
	std::free(buf);//释放
}
2.2.2 通过::operator new/delete

它与malloc的区别是, 如果内存开辟失败, 它的标志是抛出异常, 因此可以用try- catch来捕获.

例如:

cpp 复制代码
void *buf = nullptr;
try {
	buf = ::operator new(16);
}catch (const std::exception &err){
	//异常处理
}
::operator delete(buf);//释放

3. 栈区

3.1 栈区特点

  • 栈区是一种自动分配和释放的内存区域,由编译器自动管理。
  • 栈内存的分配是连续的,分配速度很快。分配的内存大小有限,通常在几MB到几GB之间。
  • 存储局部变量等短期生存的数据,变量生命周期由其作用域决定,函数执行时分配内存,函数返回时自动释放内存。

3.2 栈区代码示例

cpp 复制代码
#include <iostream>

void func() {
    int localVar = 10; // 局部变量,存储在栈区
    std::cout << "In func(): localVar = " << localVar << std::endl;
} // func 结束,局部变量 localVar 自动释放

int main() {
    func(); // 调用 func 函数
    // 在这里访问 localVar 会导致编译错误,因为它的作用域仅限于 func 函数内部
    // std::cout << "In main(): localVar = " << localVar << std::endl;
    return 0;
}

3.3 需要注意的问题

  • 使用堆区的一种常见方式, 是在栈中定义一个指针, 让这个指针指向所分配的堆空间.
  • 需要注意的是, 栈区的指针一般在代码运行结束后会被清理掉, 在它被清理掉之前, 一定记得释放它指向的堆空间 ! 不要让它所指向的堆空间成为一个垂悬的空间,可能会造成内存泄漏.
相关推荐
努力学习编程的伍大侠2 分钟前
基础排序算法
数据结构·c++·算法
yuyanjingtao1 小时前
CCF-GESP 等级考试 2023年9月认证C++四级真题解析
c++·青少年编程·gesp·csp-j/s·编程等级考试
闻缺陷则喜何志丹1 小时前
【C++动态规划 图论】3243. 新增道路查询后的最短距离 I|1567
c++·算法·动态规划·力扣·图论·最短路·路径
charlie1145141911 小时前
C++ STL CookBook
开发语言·c++·stl·c++20
小林熬夜学编程1 小时前
【Linux网络编程】第十四弹---构建功能丰富的HTTP服务器:从状态码处理到服务函数扩展
linux·运维·服务器·c语言·网络·c++·http
倔强的石头1062 小时前
【C++指南】类和对象(九):内部类
开发语言·c++
A懿轩A3 小时前
C/C++ 数据结构与算法【数组】 数组详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·数组
机器视觉知识推荐、就业指导3 小时前
C++设计模式:享元模式 (附文字处理系统中的字符对象案例)
c++
半盏茶香3 小时前
在21世纪的我用C语言探寻世界本质 ——编译和链接(编译环境和运行环境)
c语言·开发语言·c++·算法
Ronin3054 小时前
11.vector的介绍及模拟实现
开发语言·c++