C语言作用域笔记(变量在哪能见光)
写代码经常遇到变量“不认识”或者“被改乱了”的情况十有八九是 作用域 没搞明白。作用域就是变量在程序里“能见度”——在哪里能用到它在哪里看不见。这篇就把几种作用域理一遍。一、局部变量 —— 只在函数里活着在函数内部定义的变量叫局部变量包括形参也是局部。cvoidfunc(){intlocal10;// local 只在这个函数里有效}特点进入函数时创建退出函数时销毁每次调用重新初始化。只能在定义它的 那个块 里用块就是一对 {} 括起来的区域。不同函数里的同名局部变量互不干扰。块作用域在 if、for、while 里面的 {} 里定义的变量也只在那对大括号里有效。cfor(inti0;i10;i){inttempi*2;// temp 只在循环体有效printf(%d,temp);}// 这里 temp 已经没了i 在C99以后也只在这层有效二、全局变量 —— 谁都能用在所有函数 外面 定义的变量整个文件的所有函数都能访问。c#includestdio.hintglobal100;// 全局变量voidfoo(){printf(%d,global);// 能访问}intmain(){global200;foo();return0;}特点程序一开始就创建程序结束才销毁。没初始化的话会被 自动初始化为 0局部变量不会。任何函数都能改它容易出现“谁偷偷改了”的 bug尽量少用。全局变量的麻烦如果多个源文件里定义了同名的全局变量会链接冲突除非加 static 或 extern下面说。三、文件作用域 vs 函数作用域文件作用域所有全局变量和函数名从定义位置到文件末尾都可见。函数作用域只有 goto 的标签才有函数作用域你基本不用管。四、static 关键字 —— 限制可见性static 用在不同的地方意思不一样静态局部变量保留值函数内用 static 修饰局部变量它的生命周期变成整个程序运行期但作用域还是只在函数里。cvoidcounter(){staticintcount0;// 只初始化一次count;printf(%d,count);}intmain(){counter();// 1counter();// 2counter();// 3}用途函数需要记住上一次调用的结果比如生成不重复序号。静态全局变量文件内私有全局变量前面加 static它的作用域限制在 当前源文件别的文件看不到。c// file1.cstaticinthidden10;// 只在 file1.c 里能用// file2.c 想用 hidden不行编译报错。好处不同文件可以有自己的 static 全局变量不会重名冲突挺实用。静态函数文件内私有函数前加 static这个函数也只能在本文件里调用其他文件不能调用。cstaticvoidhelper(){// 只在当前.c文件内部用// do something}隔离内部实现细节避免命名冲突。五、extern —— 借用别的文件的全局变量如果一个全局变量在 file1.c 里定义想在 file2.c 里用就要用 extern 声明。c// file1.cintscore100;// file2.cexternintscore;// 告诉编译器score 在别的文件定义voidprint_score(){printf(%d,score);}注意extern 是声明不是定义不分配新的内存。六、作用域与名字遮蔽name hiding内层作用域的变量会 暂时遮蔽 外层同名的变量。内层一结束外层恢复。cintx10;// 全局voidfunc(){intx20;// 局部遮蔽全局printf(%d,x);// 输出 20{intx30;// 更内层的块遮蔽外层printf(%d,x);// 30}printf(%d,x);// 还是 20}// 全局的 x 始终是 10 除非直接 ::xC才有C没有全局域运算符特别提醒千万不要搞这种“遮蔽”别人看代码会疯。七、作用域与存储类别总结表八、几个容易乱的点for 循环里的 i 的作用域C89int i; for(i0;...)i 在循环外还活着。C99for(int i0;...)i 只在 for 的块里有效。编译的时候注意标准。大括号能创造任意块作用域有时候想限制变量的范围可以单独写一对大括号c{inttempa;ab;btemp;}// temp在这里就释放了全局变量初始值未初始化的全局/静态变量自动为 0数值或 NULL指针。局部变量不会必须手动赋值。extern和static不能同时出现在一个变量上冲突。九、实战建议能局部就别全局。函数之间通过参数和返回值交换数据别共享全局。全局变量加前缀比如 g_xxx一眼看出是全局避免无意遮蔽。静态局部变量用于计数器、单例模式但C语言里很少。static 函数一个 .c 文件里工具函数统统加 static防止和别人的库冲突。头文件里只放声明extern不放定义除非 const 或 inline。十、最后一段废话作用域像不同房间的灯——客厅的开关点亮不了卧室的灯。白天不懂夜的黑局部不懂全局的累。多写多错几次就记住哪个变量在哪儿能用了。调试时如果变量总是莫名其妙变八成是作用域或者遮蔽的问题。好了这篇够用。等你理清作用域再看static和extern就不怕了。