17. 作用域与生命周期.md 4.7 KB

17 作用域与生命周期

17.1 完整概念讲解

作用域(Scope)决定了标识符在程序的哪些部分可见,生命周期(Lifetime)决定了变量在何时分配和释放内存。

作用域类型

作用域类型 说明 示例
块作用域 仅在{}内可见 for循环内的变量
函数作用域 整个函数内可见 goto标签
文件作用域 从定义到文件末尾可见 全局变量、static函数
函数原型作用域 参数列表中可见 声明中的参数名

生命周期类型

存储类 生命周期 存储位置
自动变量(auto) 函数调用期间
静态局部变量(static local) 程序运行期间 静态存储区
全局变量 程序运行期间 静态存储区
动态分配变量 直到free()释放

关键概念

  • 局部变量:函数内定义,函数结束即销毁
  • 全局变量:函数外定义,程序结束才销毁
  • static局部变量:生命周期为程序全程,但作用域仍局限于块内
  • extern声明:引用其他文件定义的全局变量

17.2 核心API/语法

// 自动变量(默认)
int auto_var = 10;  // 等同于 auto int auto_var = 10;

// 静态局部变量
void func(void) {
    static int count = 0;  // 只初始化一次,值保留到程序结束
    count++;
}

// 全局变量
int global_var = 100;

// extern声明(引用其他文件的全局变量)
extern int global_var;

// static全局变量(限制在本文件可见)
static int file_local_var = 200;

17.3 代码示例(完整可编译,附gcc命令)

#include <stdio.h>

// 全局变量
int global_counter = 0;

// static全局变量,仅本文件可见
static int file_counter = 0;

void demonstrate_scope(void) {
    // 局部变量
    int local_var = 10;

    // 静态局部变量
    static int static_var = 0;

    printf("local_var = %d, static_var = %d\n", local_var, static_var);

    local_var += 5;
    static_var += 10;
    global_counter++;
    file_counter++;
}

void demonstrate_block_scope(void) {
    int x = 100;  // 函数作用域

    {
        int x = 200;  // 块作用域,隐藏外层x
        printf("Inner x = %d\n", x);
    }

    printf("Outer x = %d\n", x);  // 恢复外层x
}

int main() {
    printf("=== 调用前 ===\n");
    printf("global_counter = %d, file_counter = %d\n",
           global_counter, file_counter);

    for (int i = 0; i < 5; i++) {
        demonstrate_scope();
    }

    printf("\n=== 调用后 ===\n");
    printf("global_counter = %d, file_counter = %d\n",
           global_counter, file_counter);

    demonstrate_block_scope();

    // extern示例(引用其他文件的变量)
    // extern int external_var;  // 需要在其他文件定义

    return 0;
}

编译命令:

gcc -Wall -Wextra -o scope_lifetime scope_lifetime.c
./scope_lifetime

17.4 注意事项与易错点

  1. static局部变量只初始化一次:首次调用时初始化,后续调用保留上次的值
  2. 全局变量命名冲突:多个文件定义同名全局变量会导致链接错误
  3. 未初始化的全局变量:默认为0(静态存储区自动清零)
  4. 局部变量遮蔽:内层块可定义同名变量遮蔽外层变量,易导致混淆
  5. extern声明不分配内存:只是声明,定义在别处

17.5 面试要点(3-5个Q&A)

Q1: static局部变量和全局变量有什么区别? A: 生命周期相同(程序全程),但作用域不同。static局部变量只在块内可见,全局变量在声明后整个文件可见(配合extern可跨文件)。

Q2: 为什么说全局变量不是好习惯? A: 全局变量增加模块耦合,难以追踪修改,多线程环境需要同步,不利于代码复用和测试。

Q3: auto关键字在C语言中有什么作用? A: auto是默认存储类,表示自动存储(栈上)。在C语言中几乎不写,因为默认就是auto。

Q4: 如何在函数间共享数据但不使用全局变量? A: 使用static全局变量(文件作用域)、通过函数参数传递指针、使用结构体封装数据。

Q5: 文件作用域和函数作用域有什么区别? A: 文件作用域从定义处到文件末尾可见,函数作用域仅在函数内可见(如goto标签)。两者生命周期都是程序全程。