局部变量和全局变量其实更加准确点应该叫做内部变量和外部变量(在数据段内(变量也在))(Local vs. global variables) 内部变量和外部变量重名(编译器不报错)内部变量的i出现在栈空间内而不在数据段中 进而无法改变全局表变量的值 (全局变量访问数据段中的内容)
在 C 语言中,变量的作用域可以分为内部变量和外部变量,具体取决于变量的声明位置和可见范围。
内部变量(局部变量): 内部变量是在函数内部或语句块内部声明的变量。它们只在声明它们的函数或语句块内可见,出了这个范围就无法访问。内部变量在函数或语句块执行时创建,随着函数或语句块的结束而销毁。在你的代码中,int i = 5;
的声明就是一个内部变量,它只在 main
函数内可见。
int main() {
int i = 5; // 内部变量
// ...
}
外部变量(全局变量): 外部变量是在函数外部声明的变量,通常位于全局作用域中。外部变量在整个程序中都可见,可以被程序中的任何函数访问。在你的代码中,int i = 10;
的声明就是一个外部变量,它在整个程序范围内可见。
int i = 10; // 外部变量
void print(int a) {
printf("I am print i=%d\n", i); // 访问外部变量
}
int main() {
// ...
}
总结起来,内部变量是在局部作用域内声明的,只在局部范围内可见,而外部变量是在全局作用域内声明的,对整个程序可见。
局部变量与全局变量重命名——就近原则(实际获取和修改的值是局部变量的值)
经典错误:内部变量和外部变量重名(编译器不报错)内部变量的i出现在栈空间内而不在数据段中 进而无法改变全局表变量的值 (全局变量访问数据段中的内容)
#include
int i=10;//i是一个全局变量,不建议使用 及外部变量 global variables
//外部变量存储在数据段中 内部变量存储在栈中
void print(int a)
{
printf("I an print i=%d\n",i);
}
int main()
{
int i=5; //外部变量与内部变量冲突时 就近原则
printf("main i=%d\n",i); //就近原则 得5
print(5); //print(5); 函数中的 printf 语句中的 i 使用的是全局变量 i,因为在 print 函数的局
//部作用域内没有定义局部变量 i,所以就近原则将查找到全局变量 i。结果为10
}
代码中,print 函数中的 printf 语句打印的是全局变量 i 的值。虽然在 main 函数中定义了一个局部变量 i,但是在 print 函数中,全局变量 i 仍然是可见的,并且就近原则适用于同一作用域内的变量。
在 C 语言中,如果在函数内部使用了一个变量,首先会在当前作用域中查找是否有对应的局部变量,如果没有再向外部(全局作用域)查找。因此,print 函数中的 printf 语句中的 i 使用的是全局变量 i,而不是 main 函数中的局部变量 i。
代码中,print(5);
函数中的 printf
语句中的 i
使用的是全局变量 i
,因为在 print
函数的局部作用域内没有定义局部变量 i
,所以就近原则将查找到全局变量 i
。
所以,print(5) 的结果是 10,因为它打印的是全局变量 i 的值,而全局变量 i 的初始值是 10。
int i = 10;
的声明是在全局作用域中,所以它是一个全局变量,可以被程序中的任何函数访问。int i = 5;
的声明是在 main
函数内部,所以它是一个局部变量,只能在 main
函数内部访问。当在一个作用域内使用一个变量时,编程.语言首先会在当前作用域内查找是否有对应的局部变量,如果没有再向外部的父级作用域查找,直到找到该变量或者到达全局作用域。这就是所谓的就近原则(nearest enclosing scope rule)。
注:就近原则存在就意味着局部变量与全局变量重命名
#include
int i=10;//i是一个全局变量,不建议使用 及外部变量 global variables
//外部变量存储在数据段中 内部变量存储在栈中
void print(int i)//形参可以看作一个局部变量
{
printf("I an print i=%d\n",i);
}
int main()
{
printf("main i=%d\n",i); //就近原则 得10 顺序原则其距离全局变量应该是最近的
int i=5; //外部变量与内部变量冲突时(同名) 就近原则 (因为全局变量会由于 "遮蔽" 效应而优先于同名的局部变量。)
//但是此处由于声明顺序的原因及printf()函数是在其之上的 顺序原则其距离全局变量应该是最近的
print(3); //就近原则 就近于函数内部 函数内部出现同名局部变量 故就近于内部局部变量
}
就近原则(同名情况下才有)指的是在代码中从上到下的顺序中,离引用变量最近的那个变量会被选择。在 C 语言中,作用域是根据代码的结构来确定的,而变量的声明顺序以及作用域的嵌套关系都影响着就近原则。
代码中的全局变量 int i = 10;
的声明在 printf("main i=%d\n", i);
附近,因此就近原则会选择这个全局变量(执行顺序由上到下原则)
当你在某个作用域内引用一个变量时,编译器会从内向外查找该变量的声明,选择距离引用最近的那个声明。如果在当前作用域内没有找到声明,编译器会继续向上查找直到找到合适的声明或者到达全局作用域。
main函数中 调用函数的就近原则 是就近于函数内部 函数内部出现同名局部变量 故就近于内部局部变量结果为3
题中void print(int a) 换成了void print(int i)
若未出现同名变量即仍是void print(int a) 则仍和全局变量保持一致 因为调用函数的就近原则 是就近于函数内部
#include
int i=10;//i是一个全局变量,不建议使用 及外部变量 global variables
//外部变量存储在数据段中 内部变量存储在栈中
void print(int a)
{
printf("I an print i=%d\n",i);
}
int main()
{
i=3;
printf("main i=%d\n",i); //就近原则 得10 顺序原则其距离全局变量应该是最近的
int i=5;//经典错误(重名——>采用就近原则)
print(5);
}
代码中,i=3;
语句位于 main
函数的开头。这导致全局变量 int i = 10;
的值被修改为 3
(数据被存储到数据段内)
因为此时 i
是全局变量。因此,全局变量的值在 main
函数内被更新为 3
,然后在 printf("main i=%d\n", i);
中被引用,因此输出结果是 3
而不是 10
。
由于全局变量 i
的值被修改(数据被存储到数据段内修改了全局变量),当 print(5);
被调用时,print
函数中打印的全局变量 i
也是被修改后的值,即 3
。
关于存储位置的部分,全局变量 i
存储在数据段中,而局部变量 int i = 5;
存储在栈上。修改全局变量 i
的值会影响全局范围内的这个变量。
#include
int i=10;//i是一个全局变量,不建议使用 及外部变量 global variables
//外部变量存储在数据段中 内部变量存储在栈中
void print(int a)
{
printf("I an print i=%d\n",i);
}
int main()
{
printf("main i=%d\n",i); //就近原则 得10 顺序原则其距离全局变量应该是最近的
int i=5;//经典错误(重名——>采用就近原则)
i=3; //修改的是局部变量 i 的值,而不是全局变量。
print(5);// 10
}
在这个情况下,int i=5;
是在 main
函数的局部作用域中声明的一个新的局部变量,它覆盖了全局变量 int i=10;
。然后,i=3;
修改的是局部变量 i
的值,而不是全局变量。
在 print(5);
中,print
函数中引用的是全局变量 i
,而不是 main
函数内部的局部变量。由于全局变量 i
的值一直为 10
,因此 print
函数输出的是全局变量的值。
虽然全局变量在编程中是有效的工具,但是它们的使用也带来了一些潜在的问题。以下是一些不建议过度使用全局变量的原因:
1. 命名空间污染(Namespace Pollution):全局变量可以在整个程序中访问,容易导致命名冲突。如果多个文件都使用了相同名称的全局变量,可能会引起不可预测的错误。
2. 可维护性: 全局变量使得代码更难维护。当程序规模增大时,全局变量的修改可能会在不同的地方产生意外的影响,增加了代码的复杂性。
3. 安全性:全局变量的值可以被程序中的任何地方修改,这可能导致难以调试的错误。在大型程序中,很难跟踪全局变量的状态。
4. 可移植性: 使用全局变量可能使得代码在不同的上下文中更难以移植。函数内部使用的变量通常更容易控制和理解。
5. 并发性:在多线程或并发环境中,全局变量可能引发竞争条件,导致不确定的行为。使用局部变量可以避免这种问题。
6. 测试: 单元测试和模块测试通常更容易应用于使用局部变量的函数,因为它们更容易理解和隔离。
全局变量在某些情况下可能是有用的,但在设计和编写代码时,通常更推荐使用局部变量和传递参数的方式,以提高代码的可读性、可维护性和安全性。
目前很多大厂也是不允许使用全局变量的 所以请记住:
不要使用全局变量!!! 不要使用全局变量!!! 不要使用全局变量!!!