C语言内存学习

  1. 在c语言中内存包括 堆内存、栈内存、全局常态区、常量区


  2. 变量分为:

    按存储类别分为自动变量、静态变量、寄存器变量(不在主存中,而在 CPU 寄存器里)、外部变量

    按作用域分类:局部变量、全局变量、形参

    按生命周期分类:自动存储期、静态存储期、动态存储期

    按数据类型分类:基本类型、派生类型、空类型

  3. 存储类别

    4.1. 自动变量(Automatic)

c 复制代码
void func() {
    int x = 10;        // 等价于 auto int x = 10;   存放在栈上
    char c;            // 未初始化 → 垃圾值!
}

auto(通常省略),存储在栈(stack),函数调用时分配,函数返回时自动释放,不会自动初始化 → 值为垃圾数据

4.2. 静态变量(Static)

c 复制代码
// 全局静态(仅本文件可见)
static int global_count = 0;   // → .data 段

void counter() {
    static int local_count = 0; // 只初始化一次,函数退出不销毁   → .bss 段(值为 0)
    local_count++;
    static char msg[] = "Hi";    // → .data 段(含字符串)
    printf("%d\n", local_count);
}

.bss(Block Started by Symbol)段不占可执行文件空间,运行时由 OS 清零。

全局静态变量(文件作用域 + static)

局部静态变量(函数内 + static)

如果显式初始化(如 = 5)→ 已初始化数据段(.data)

如果未初始化或初始化为 0 → 未初始化数据段(.bss)

存储在数据段(.data 或 .bss)

程序启动时分配,结束时释放

自动初始化为 0(即使你没写)

生命周期贯穿整个程序

4.3. 外部变量(External)

c 复制代码
// file1.c
int global_var = 42; // 定义(分配内存)// 定义 → .data 段

// file2.c
extern int global_var; // 声明(不分配内存,引用 file1.c 的变量)

外部变量和普通全局变量内存位置相同,extern 只是"告诉编译器这个变量在别处定义"。

本质:就是全局变量,只是用 extern 在其他文件中声明

内存位置:

显式初始化 → .data 段

未初始化 → .bss 段

4.4. 寄存器变量(Register)

c 复制代码
register int i; // 建议编译器将 i 放入 CPU 寄存器(加速访问)

⚠️ 现代编译器优化能力强,通常忽略 register,且不能取地址(&i 非法)

编译器可能忽略该请求(现代优化器自行决定)

不能取地址(&x 非法)→ 因为寄存器没有内存地址

访问速度最快(比栈快得多)

补充:

局部变量 → 用自动变量(栈):高效、安全

需要保持状态 → 用 static:避免全局污染

跨文件共享 → 用 extern + 全局变量:谨慎使用

不要滥用 register:让编译器优化

永远初始化局部变量:避免栈上的垃圾值

  1. 作用域

全局变量默认具有外部链接性(可被其他文件通过 extern 访问),加 static 可变为内部链接性(仅本文件可见)。

局部变量 栈区(Stack)

全局变量 已初始化的全局变量:存储在 .data 段(初始化数据段)。

未初始化或初始化为零的全局变量:存储在 .bss 段(未初始化数据段,程序启动时自动清零)。

形参(形式参数)栈区(Stack)

  1. 生命周期


    栈溢出:栈区空间有限(通常几MB),递归过深或局部变量过大可能导致栈溢出。
    内存泄漏:动态分配的内存未释放会导致泄漏,长期运行的程序可能因此崩溃。
    野指针:释放堆内存后未置空指针,再次访问会导致未定义行为。
    静态变量的初始化:静态局部变量仅在第一次进入作用域时初始化,后续调用保留值。
  2. 数据类型
c 复制代码
int age;           // 基本类型
char name[20];     // 数组(派生)
struct Point p;    // 结构体(派生)
void *ptr;         // void 指针
  1. 对比

    优先使用局部变量(减少全局状态,提高模块化)
    全局变量加 static(除非明确需要跨文件共享)
    局部变量务必初始化(避免垃圾值)
    慎用 register(让编译器优化)
    动态内存用 malloc/free(不属于"变量种类",但需手动管理)
c 复制代码
#include <stdio.h>

static int global_static = 100; // 全局、静态存储期、内部链接

void func() {
    auto int local_auto = 200;   // 局部、自动存储期(auto 可省略)
    static int local_static = 300; // 局部作用域,静态存储期
    
    printf("local_static = %d\n", local_static);
    local_static++; // 下次调用会保留值
}

int main() {
    func(); // 输出 300
    func(); // 输出 301
    return 0;
}

栈:主要用于存储局部变量(无论是基本类型还是派生类型),随着函数调用进入和退出而自动分配和回收。

数据段:用于存储全局变量和静态变量,这些变量在程序运行期间一直存在。

堆:用于动态内存分配,适用于那些需要在运行时确定大小的数据结构。

只读数据段:存储常量数据,程序运行过程中不可修改。

相关推荐
回眸&啤酒鸭2 天前
【回眸】解放双手,实现语音刷抖音小巧思
c·全志h616
麦烤楽鸡翅4 天前
简单迭代法求单根的近似值
java·c++·python·数据分析·c·数值分析
铁手飞鹰4 天前
单链表(C语言,手撕)
数据结构·c++·算法·c·单链表
moringlightyn8 天前
Linux---进程状态
linux·运维·服务器·笔记·操作系统·c·进程状态
树在风中摇曳8 天前
数据结构与算法基础入门 —— 从概念到复杂度理解
开发语言·c
lucky_dog9 天前
c语言——while循环续,for循环
c
树在风中摇曳11 天前
每日小练——宏的运用
c
huangyuchi.18 天前
【Linux网络】Socket编程实战,基于UDP协议的Dict Server
linux·网络·c++·udp·c·socket
moringlightyn20 天前
进度条+ 基础开发工具----版本控制器git 调试器gdb/cgdb
笔记·git·其他·c·调试器·gdb/cgdb·进度条 倒计时