在 C 语言中,变量有一定的作用域(也就是变量的有效范围)。根据变量定义位置的不同,可以分为以下 2 种。
- 全局变量。
- 局部变量。
C 全局变量
在 C 语言中,全局变量指的是在所有函数之外定义的变量。对于全局变量来说,它的作用范围是从定义处到整个 C 程序结束。也就是说,程序中的任何函数都可以访问和修改全局变量的值。
示例 1:C 定义全局变量
#include <stdio.h>
// 定义全局变量
int year = 2030;
void fn(void)
{
// 在 fn() 函数中访问全局变量
printf("%d\n", year);
}
int main(void)
{
fn();
// 在 main() 函数中访问全局变量
printf("%d", year);
return 0;
}运行结果如下。
2030
2030分析:
C 语言中的全局变量在整个程序范围内有效,所有函数都可以访问和修改它。
示例 2:全局变量会默认初始化
#include <stdio.h>
// 定义全局变量
int a;
float b;
char c;
int main(void)
{
// 在 main() 函数中访问全局变量
printf("%d\n", a);
printf("%f\n", b);
printf("%c\n", c);
return 0;
}运行结果如下。
0
0.000000
(空字符)分析:
如果全局变量在定义时没有显式地初始化,它们默认会被自动初始化。其中 int 类型默认初始化为 0,float 类型默认初始化为 0.000000,而 char 类型默认初始化为空字符(即 ASCII 值为 0 的字符 '\0')。
提示: 使用关键字 static 修饰的全局变量,其作用域会被限制在当前源文件内。也就是说,其他源文件无法通过 extern 关键字访问该静态全局变量。这种方式有助于实现模块化和信息隐藏。
C 局部变量
在 C 语言中,局部变量指的是在 “函数” 内部定义的变量。对于局部变量来说,它只能在其被定义的函数内部被访问到。当函数执行完毕后,局部变量会被销毁,其占用的内存也会被释放。
示例 3:C 定义局部变量
#include <stdio.h>
void fn(void)
{
// 定义局部变量
int year = 2030;
// 访问局部变量
printf("%d", year);
}
int main(void)
{
fn();
// 尝试在 main() 中访问局部变量
printf("%d", year);
return 0;
}运行结果如下。
(报错)error: 'year' undeclared (first use in this function);分析:
C 语言中的局部变量只能在当前函数内部可以被访问到,而无法在其他函数中被访问到。
在下面代码中,我们可以直观地看出全局变量和局部变量的位置区别。
#include <stdio.h>
int a = 10; // 这是全局变量
void fn(void)
{
int b = 20; // 这是局部变量
printf("%d", b);
}
int main(void)
{
int c = 30; // 这是局部变量
printf("%d", c);
return 0;
}示例 4:static 局部变量
#include <stdio.h>
void counter()
{
// 静态局部变量,只初始化一次
static int count = 0;
count++;
printf("函数被调用了 %d 次\n", count);
}
int main(void)
{
counter();
counter();
counter();
return 0;
}运行结果如下。
函数被调用了 1 次
函数被调用了 2 次
函数被调用了 3 次分析:
使用关键字 static 修饰的局部变量,其生命周期会持续到程序结束,但其作用域仍然限制在定义它的函数内部。该静态局部变量在程序运行前就已经完成了初始化(且只能初始化一次),后续的函数调用会保持上次的值。
注意: C 语言中静态局部变量的初始值必须是常量。
C 全局变量与局部变量同名
在 C 语言中,如果在函数内部定义了一个与全局变量同名的局部变量,那么在该函数内部,局部变量会 “屏蔽” 全局变量。也就是说,函数内部访问的是局部变量,而不是全局变量。
示例 5:全局变量与局部变量同名
#include <stdio.h>
// 定义全局变量
int year = 2030;
void getYear(void)
{
// 定义与全局变量同名的局部变量
int year = 2077;
printf("%d\n", year); // 访问的是局部变量
}
int main(void)
{
printf("main(修改前):%d\n", year); // 访问的是全局变量
getYear();
printf("main(修改后):%d\n", year); // 访问的仍然是全局变量
return 0;
}运行结果如下。
main(修改前):2030
2077
main(修改后):2030分析:
在 getYear() 函数内部,局部变量 year 的值为 2077,它与全局变量 year 互不影响。在 main() 函数中,访问的仍然是全局变量 year。
extern 关键字
如果一个全局变量在一个源文件中定义,而需要在另一个源文件中使用,此时可以使用 extern 关键字在使用的源文件中声明该全局变量。这告诉编译器该变量已经在其他地方定义过了。
在当前项目的根目录中有 2 个文件:utils.c 和 main.c,整个项目结构如下图所示。

其中,utils.c 代码如下:
// 定义全局变量
int year = 2030;示例 6:使用 extern 关键字(main.c)
#include <stdio.h>
// 声明在 utils.c 中定义的全局变量
extern int year;
int main(void)
{
printf("%d", year);
return 0;
}然后我们需要使用 gcc 同时编译 main.c 和 utils.c,也就是在 VSCode 中先执行 “gcc main.c utils.c -o output”,然后再运行 “./output”,其结果如下。
2030最后来总结一下,在使用全局变量和局部变量时,小伙伴们要注意以下几点:
- 尽量减少全局变量的使用:过多地使用全局变量可能会导致程序的可维护性降低,因为全局变量可以在程序的任何地方被修改,这使得跟踪变量的变化变得困难,并且容易产生意想不到的副作用。
- 局部变量优先:在能够满足需求的情况下,应该优先使用局部变量。因为局部变量的作用域仅限于函数内部,有助于提高代码的模块性和独立性。
- 注意变量的初始化:在使用变量之前务必对其进行初始化,特别是局部变量,这样可以避免使用未定义的值。全局变量通常会被默认初始化,但显式初始化可以提高代码的可读性。
- 避免全局变量与局部变量同名:虽然 C 语言允许全局变量和局部变量同名,但这会降低代码的可读性,容易引起混淆。我们应该尽量避免这种情况,或者使用清晰的命名约定来区分它们。
