scope / 作用域(C变量的作用域)
参考:C Primer Plus 第6版 第12章 存储类别、链接和内存管理
目录1. 定义
描述程序中可以访问identifier(标识符)的区域
2. 分类
scope可以分为四类:
2.1. block scope / 块作用域
2.1.1. 定义
- block/块是用一块花括号括起来的代码区域
- 块作用域变量的范围是从定义处到包含该定义块的末尾
- 声明在内层块中的变量,其作用域仅局限于该声明所在的块
2.1.2. 函数的形式参数
- 虽然函数的形式参数声明在函数的花括号之前,但是它们也具有块作用域,属于函数体这个块
2.1.3. 没有花括号的块
之前,具有块作用域的变量都必须声明在块的开头,C99标准放开了这个限制:作为循环或者if语句的一部分,即便不使用花括号,也是一个块。
所以for循环语句可以这样定义:for(int i=0; i<10; i++)
更完整地说,整个循环是它所在块的子块,循环体是整个循环块的子块;if语句是一个块,与其相关联的子语句是if语句的子块,这其中包含着一种嵌套关系。
#include <stdio.h>
int main()
{
int n = 8;
printf("Initially, n = %d at %p\n", n, &n);
for (int n = 1; n < 3; n++)
printf("loop 1: n = %d at %p\n", n, &n);
printf("After loop 1, n = %d at %p\n", n, &n);
for (int n = 1; n < 3; n++)
{
printf("loop 2 index n: n = %d at %p\n", n, &n);
int n = 6;
printf("loop 2: n = %d at %p\n", n, &n);
n++;
}
printf("After loop 2, n = %d at %p\n", n, &n);
return 0;
}
该程序的输出如下:
Initially, n = 8 at 000000950FDFF6D4
loop 1: n = 1 at 000000950FDFF6F4
loop 1: n = 2 at 000000950FDFF6F4
After loop 1, n = 8 at 000000950FDFF6D4
loop 2 index n: n = 1 at 000000950FDFF714
loop 2: n = 6 at 000000950FDFF734
loop 2 index n: n = 2 at 000000950FDFF714
loop 2: n = 6 at 000000950FDFF734
After loop 2, n = 8 at 000000950FDFF6D4
进入循环之后,隐藏了原有的n;
然后在循环体中又声明了一个n,隐藏了索引n;
循环单次迭代结束之后,声明在循环体中的n消失,循环头仍调用到索引n;
当整个循环完成之后,原始的n重新起作用。
简而言之,索引n的作用域是整个循环,而定义在循环体中变量n的作用域只有单个循环。
!!!没必要在程序中使用相同的变量名
2.2. function scope / 函数作用域
- 仅用于goto语句的标签
- 即使一个标签首次出现在函数的内层块中,它的作用域也将延伸至整个函数(是整个函数而非块)
- 标签的函数作用域防止在两个块中使用相同的标签所导致的混乱
2.3. function prototype scope / 函数原型作用域
- 用于函数原型中的形参名
- 函数原型作用域的范围是从形参定义处到原型声明结束(可以理解为小括号内)
- 函数原型声明中的标识符可以与函数定义中说明的标识符名称不同,只要让函数声明和函数定义中小括号内每个变量的类型及数目一致即可,也可以省略掉参数名。
double max(double x, double y);
double max(double, double);
//两者均可
2.4. file scope / 文件作用域
- 从定义处到该定义所在的文件末尾均可见
- 文件作用域变量也被称作全局变量 global variable
3. 总结
- scope的定义
- scope的分类以及各自的含义
Others:
- goto标签如何使用?
- 什么是函数原型?