文章目录
1、作用域
所谓
作用域
,就是变量的有效范围。
C 语⾔的变量作用域主要有两种:块作用域(block scope)和 文件作用域(file scope)。
2、代码块(程序块)
所谓代码块
(程序块),就是由 { }
包围起来的代码。代码块在 C 语言中随处可见,例如函数体、选择结构、循环结构等。 C 语言允许在代码块内部定义变量,这样的变量具有块级作用域;换句话说,在代码块内部定义的变量只能在代码块内部使用,出了代码块就无效了。
3、变量的作用域与存储类型
3.1、引出了两个问题
- 第一,每一个变量在什么范围内起作用。【作用域问题】
- 第二,每一个变量何时生成、何时消失,在程序中能存在多久。【生命周期问题】
3.2、生命周期问题
变量的生命周期取决于变量的存储类型
, C 语言中变量有 4 种不同的存储类型,分别用关键字 auto、static、extern 、register 表示。
这个我们后面再讲解。
3.3、二者的关系
一个变量如果不在其生命周期,肯定无作用域可言;如果在其生命周期,也未必一直起作用,即使起作用也是在特定的范围内。
3.4、变量与作用域
在 (2.13)形参和实参 中提到,形参变量要等到函数被调用时才分配内存,调用结束后立即释放内存。这说明形参变量的作用域非常有限,只能在函数内部使用,离开该函数就无效了。
C 语言中所有的变量
都有自己的作用域
。
有些变量可以在所有代码文件中使用,有些变量只能在当前的文件中使用,有些变量只能在函数内部使用,有些变量只能在 for 循环内部使用。
决定变量作用域的是
变量的定义位置
。在不同位置定义的变量,它的作用域是不一样的。
位置有 3 种:
- 函数体外:在函数块内部的
局部变量
–块作用域; - 函数体内:在所有函数外部的
全局变量
–文件作用域; - 函数语句块内:
形式参数
在函数参数定义中;
接下来解释一下局部变量和全局变量。
4、局部变量
4.1、定义
定义在某个函数或块的内部声明的变量
称为局部变量
。
- 它们只能被该函数或该代码块内部的语句使用。
- 局部变量在函数外部是不可知的。
- 它的作用域仅限于函数内部,离开该函数后就是无效的。
4.2、实例
在这里,所有的变量( a、b、c)都是 main() 函数的局部变量。
#include <stdio.h>
int main ()
{
/* 局部变量声明 */
int a, b;
int c;
/* 实际初始化 */
a = 10;
b = 20;
c = a + b;
printf ("value of a = %d, b = %d and c = %d\n", a, b, c);
return 0;
}
4.3、局部变量的 4 点说明
- 在 main 函数中定义的变量也是局部变量,只能在 main 函数中使用;同时,main 函数中也不能使用其它函数中定义的变量。main 函数也是一个函数,与其它函数地位平等。
形参变量、在函数体内定义的变量
都是局部变量。实参给形参传值的过程也就是给局部变量赋值的过程。- 可以
在不同的函数中使用相同的变量名
,它们表示不同的数据,分配不同的内存,互不干扰,也不会发生混淆。
如下案例:
#include <stdio.h>
/* 全局变量声明 */
int g = 20;
int main ()
{
/* 局部变量声明 */
int g = 10;
printf ("value of g = %d\n", g);
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
value of g = 10
- 在
语句块
中也可定义变量,它的作用域只限于当前语句块。
5、全局变量
5.1、定义
定义在所有函数外部定义的变量
称为全局变量
。
- 全局变量是定义在函数外部,通常是在程序的顶部。
- 全局变量在整个程序生命周期内都是有效的,全局变量可以被任何函数访问。
也就是说,全局变量在定义后整个程序中都是可用的。
- 它的作用域默认是整个程序,也就是所有的源文件,包括 .c 和 .h 文件。
5.2、实例 1
值输出
void func() {
x = 1; //报错
y = 2;
}
float x,y; //全局变量
int main() {
x = 1; //正确
y = 2;
return 0;
}
x、y 都是在函数外部定义的全局变量。C 语言代码是从前往后依次执行的,由于 x、y 定义在函数 func() 之后,所以在 func() 内无效;但在 func() 和 main() 内都有效。
5.3、实例 2
根据长方体的长宽高求它的体积以及三个面的面积
#include <stdio.h>
int s1, s2, s3; //面积
int vs(int a, int b, int c){
int v; //体积
v = a * b * c;
s1 = a * b;
s2 = b * c;
s3 = a * c;
return v;
}
int main(){
int v, length, width, height;
printf("Input length, width and height: ");
scanf("%d %d %d", &length, &width, &height);
v = vs(length, width, height);
printf("v=%d, s1=%d, s2=%d, s3=%d\n", v, s1, s2, s3);
return 0;
}
运行结果:
Input length, width and height: 10 20 30↙
v=6000, s1=200, s2=600, s3=300
根据题意,我们希望借助一个函数得到三个值:体积 v 以及三个面的面积 s1、s2、s3。全局变量的作用域是整个程序,在函数 vs() 中修改 s1、s2、s3 的值,能够影响到包括 main() 在内的其它函数。
6、局部变量和全局变量
6.1、初始化局部变量和全局变量
当
局部变量
被定义时,系统不会对其初始化
,您必须自行对其初始化。定义全局变量
时,系统会自动对其初始化
。
如下所示:
数据类型 | 初始化默认值 |
---|---|
int | 0 |
char | ‘\0’ |
float | 0 |
double | 0 |
pointer | NULL |
注意:
正确地初始化变量是一个良好的编程习惯,否则有时候程序可能会产生意想不到的结果,因为未初始化的变量会导致一些在内存位置中已经可用的垃圾值。
6.2、局部变量和全局变量综合示例
输出变量的值
#include <stdio.h>
int n = 10; //全局变量
void func1(){
int n = 20; //局部变量
printf("func1 n: %d\n", n);
}
void func2(int n){
printf("func2 n: %d\n", n);
}
void func3(){
printf("func3 n: %d\n", n);
}
int main(){
int n = 30; //局部变量
func1();
func2(n);
func3();
//代码块由{}包围
{
int n = 40; //局部变量
printf("block n: %d\n", n);
}
printf("main n: %d\n", n);
return 0;
}
运行结果:
func1 n: 20
func2 n: 30
func3 n: 10
block n: 40
main n: 30
- 代码中虽然定义了多个同名变量 n,但它们的作用域不同,所有不会产生命名冲突。
下面是对输出结果的详细分析:
- 对于 func1(),输出结果为 20,显然使用的是 func1() 内部的 n,而不是外部的 n。
- 调用 func2() 时,会把 main() 中的实参 n 传递给 func2() 中的形参 n,此时形参 n 的值变为 30。形参 n 也是局部变量,所以就使用它了。
- func3() 输出 10,使用的是全局变量,因为在 func3() 中不存在局部变量 n,所以编译器只能到函数外部,也就是全局作用域中去寻找变量 n。
- main() 中 printf() 语句输出 30,说明使用的是 main() 中的 n,而不是外部的 n。
7、形参和局部变量
函数的参数,被当作该函数内的局部变量,如果与全局变量同名
它们会优先使用。
下面是一个实例:
#include <stdio.h>
/* 全局变量声明 */
int a = 20;
int main ()
{
/* 在主函数中的局部变量声明 */
int a = 10;
int b = 20;
int c = 0;
int sum(int, int);
printf ("value of a in main() = %d\n", a);
c = sum( a, b);
printf ("value of c in main() = %d\n", c);
return 0;
}
/* 添加两个整数的函数 */
int sum(int a, int b)
{
printf ("value of a in sum() = %d\n", a);
printf ("value of b in sum() = %d\n", b);
return a + b;
}
当上面的代码被编译和执行时,它会产生下列结果:
value of a in main() = 10
value of a in sum() = 10
value of b in sum() = 20
value of c in main() = 30
全局变量与局部变量在内存中的区别:
- 全局变量保存在内存的全局存储区中,占用静态的存储单元;
- 局部变量保存在栈中,只有在所在函数被调用时才动态地为变量分配存储单元。
代码中虽然定义了多个同名变量 n,但它们的作用域不同,在内存中的位置(地址)也不同,所以是相互独立的变量,互不影响,不会产生重复定义(Redefinition)
错误。
C 语言规定,只能从小的作用域向大的作用域中去寻找变量,而不能反过来,使用更小的作用域中的变量。对于 main() 函数,即使代码块中的 n 离输出语句更近,但它仍然会使用 main() 函数开头定义的 n,所以输出结果是 30。
8、关于变量的命名
每一段可运行的 C 语言代码都包含了多个作用域,即使最简单的 C 语言代码也是如此。
C 语言规定,在同一个作用域中不能出现两个名字相同的变量,否则会产生命名冲突;但是在不同的作用域中,允许出现名字相同的变量,它们的作用范围不同,彼此之间不会产生冲突。
这句话有两层含义:
- 不同函数内部可以出现同名的变量,不同函数是不同的局部作用域;
- 函数内部和外部可以出现同名的变量,函数内部是局部作用域,函数外部是全局作用域。
不同函数内部的同名变量是两个完全独立的变量,它们之间没有任何关联,也不会相互影响。
请看下面的代码:
#include <stdio.h>
void func_a(){
int n = 100;
printf("func_a: n = %d\n", n);
n = 86;
printf("func_a: n = %d\n", n);
}
void func_b(){
int n = 29;
printf("func_b: n = %d\n", n);
func_a(); //调用func_a()
printf("func_b: n = %d\n", n);
}
int main(){
func_b();
return 0;
}
运行结果:
func_b: n = 29
func_a: n = 100
func_a: n = 86
func_b: n = 29
下面是对输出结果的详细分析:
func_a() 和 func_b() 内部都定义了一个变量 n,在 func_b() 中,n 的初始值是 29,调用 func_a() 后,n 值还是 29,这说明 func_b() 内部的 n 并没有影响 func_a() 内部的 n。这两个 n 是完全不同的变量,彼此之间根本“不认识”,只是起了个相同的名字而已,这就好像明星撞衫,北京和云南都有叫李红的,赶巧了而已。
每日一更!
公众号、优快云等博客:小菜狗编程笔记
谢谢点赞关注哈!目前在飞书持续优化更新~
日更较慢有需要完整笔记请私我,C/C++/数据结构-算法/单片机51-STM32-GD32-ESP32/嵌入式/Linux操作系统/uboot/Linux内核-驱动-应用/硬件入门-PCB-layout/Python/后期小程序和机器学习!