国际访客建议访问 Primers 编程伙伴 国际版站点 > C 教程 > 作用域 以获得更好的体验。

# C 语言的作用域

作用域是指程序中定义的变量(或其他标识)符的可见性和生命周期范围,决定了变量(或其他标识)可以在哪些位置被使用。

在 C 语言中,任意一对花括号({})就是一个独立的作用域,在作用域中定义的变量称为该作用域的 局部变量(Local Variables)

变量在定义时占用相应的内存空间,在离开作用域时其占用的内存被释放。

# 函数作用域

典型的作用域环境就是函数。例如:

void foo()
{
    int x = 10;  // x 是函数 foo 内的局部变量
    int y = 20;  // y 是函数 foo 内的局部变量
}

void bar()
{
    int x = 6;  // x 是函数 bar 内的局部变量
}
  • 函数 foo 中定义了两个局部变量 xy,函数 bar 中不能访问这两个变量

  • 函数 bar 中中定了局部变量 x,虽然和函数 foo 中的变量 x 同名,但它们毫无关系,函数 foo 中不能访问这个变量

函数的形式参数也是该函数的局部变量。

# 块作用域

条件语句、循环语句、分支语句等也是独立的作用域。例如:

int main()
{
    // x 是函数 main 内的局部变量
    int x = 1;

    if (1)
    {
        // if 块作用域
        // 作为 main 函数作用域的子作用域,可以访问 x

        // y 是 if 块内的局部变量
        int y = 2;
    }
    else
    {
        // else 块作用域
        // 作为 main 函数作用域的子作用域,可以访问 x
        // 不能访问 if 块作用域中的 y

        // z 是 else 块内的局部变量
        int z = 3;
    }

    while (0)
    {
        // while 块作用域
        // 作为 main 函数作用域的子作用域,可以访问 x
        // 不能访问 if 块作用域中的 y
        // 不能访问 else 块作用域中的 z

        // y 是 while 块内的局部变量,与前面 if 块中的 y 同名,但毫无关系
        int y = 4;
    }

    for (int i = 0; i < 10; i+=1) // 这里定义的 i 也是 for 块作用域内的局部变量
    {
        // for 块作用域
        // 作为 main 函数作用域的子作用域,可以访问 x
        // 不能访问 if 块作用域中的 y
        // 不能访问 else 块作用域中的 z
        // 不能访问 while 块作用域中的 y

        // z 是 for 块内的局部变量,与前面 else 块中的 z 同名,但毫无关系
        int z = 5;
    }

    // 直接使用花括号创建块作用域
    {
        // 作为 main 函数作用域的子作用域,可以访问 x
        // 不能访问 if 块作用域中的 y
        // 不能访问 else 块作用域中的 z
        // 不能访问 while 块作用域中的 y


        // 在此之前访问的 x 是 main 函数前面定义的 x
        // x 是块内的局部变量,与 main 函数前面定义的 x 同,但毫无关系
        int x = 6; // 与外层变量同名,容易引起混淆,不建议使用
        // 在此之后范围的 x 是此处新定义的 x

    }

    return 0;
}
flowchart 
    main --可访问--> x1["x"]

    y1["y"] ~~~ if --可访问--> y1
    z1["z"] ~~~ else --可访问--> z1
    y2["y"] ~~~ while --可访问--> y2
    z2["z"] ~~~ for --可访问--> z2
    x3["x"] ~~~ block --可访问--> x3
    i ~~~ for --可访问--> i

    if["if 块"] --可访问--> main
    else["else 块"] --可访问--> main
    while["while 块"] --可访问--> main
    block["无名块"] --可访问--> main
    for["for 块"] --可访问--> main
  • 函数 main 中定义了局部变量 x,函数内部的其它子作用域可以访问它

  • if 块中定义了局部变量 y,其它作用域不能访问它

  • else 块中定义了局部变量 z,其它作用域不能访问它

  • while 块中定义了局部变量 y,其它作用域不能访问它

    • 此处的 yif 中的 y 同名,但毫无关系

  • for 块中定义了局部变量 iz,其它作用域不能访问它

    • 此处的 zelse 中的 z 同名,但毫无关系

  • 末尾处的块作用域中定义了局部变量 x,其它作用域不能访问它

    • 此处的 xmain 函数前面定义的 x 同名,但毫无关系

注意,在末尾的块作用域中可以访问 main 函数前面定义的变量 x。因此:

  • 在其内部定义 x 之前,访问的 xmain 函数前面定义的 x

  • 在其内部定义 x 之后,访问的 x 是块内部新定义的 x

这种与外部变量同名的局部变量被称为影子(Shadow)变量,由于极易引起混淆,因此建议避免使用。

# 在 switch 中定义局部变量

分支语句和上述其它块一样是独立的作用域,但其存在一些特别之处。

下面代码是错误的:

int x = 2;
switch (x)
{
case 1:
    int n = 10; // n 是 switch 块内的局部变量
    break;

case 2:
    printf("%d\n", n); // 访问局部变量 n
    break;
}

这段代码从作用域规则上来看没有问题:在 switch 块中定义了局部变量 n,然后在作用域内访问它。

但当 x 的值是 2 是,case 1 不会被执行,因此变量 n 不会被定义,也就无法被访问。

因此,语法规定 switch 块作用域中不能直接定变量;如果需要定义变量,则必须使用花括号({})创建新的块作用域。

例如:

switch (x)
{
case 1:
    {
        int n = 10; // n 是子块内的局部变量,其它作用域不能访问它
        break;
    }

case 2:

    {
        // 这里不能范围 case 1 中的 n,但可以重新定义一个

        int n = 20; // n 是子块内的局部变量,其它作用域不能访问它
        printf("%d\n", n); // 访问局部变量 n
        break;
    }
}
  • case 1 的块中定义了局部变量 n,在 case 2 中不能访问它 case 2 中另外定义了一个局部变量 n,它与 case 1 块中的 n 没有任何关系

# 全局作用域

在所有块之外的作用域被称为全局作用域,全局作用域中定义的变量称为 全局变量(Global Variables)

例如:

#include <stdio.h>

// 定义全局变量
const double PI = 3.1415926;

/*********************************************
 * @brief 计算圆的周长
 * @param r 半径
 * @return 圆的周长
 ********************************************/
double circle_circumference(double r)
{
    return 2 * PI * r; // 访问全局变量 PI
}

/*********************************************
 * @brief 计算圆的面积
 * @param r 半径
 * @return 圆的面积
 ********************************************/
double circle_area(double r)
{
    return PI * r * r; // 访问全局变量 PI
}

int main(void)
{
    double r = 10.0;
    double circumference = circle_circumference(r);
    double area = circle_area(r);

    printf("半径为 %f 的圆,周长为 %f,面积为 %f\n", r, circumference, area);

    return 0;
}

运行结果:

半径为 10.000000 的圆,周长为 62.831852,面积为 314.159260

这个示例中定义了全局变量 PI,在函数 circle_circumferencecircle_area 均可访问该变量。

本文 更新于: 2025-11-27 09:38:06 创建于: 2025-11-27 09:38:06