局部变量和全局变量

局部变量和全局变量的介绍

局部变量和全局变量其实更加准确点应该叫做内部变量外部变量(在数据段内(变量也在)Local vs. global variables) 内部变量和外部变量重名(编译器不报错)内部变量的i出现在栈空间内而不在数据段中 进而无法改变全局表变量的值 (全局变量访问数据段中的内容)

局部变量和全局变量_第1张图片

在 C 语言中,变量的作用域可以分为内部变量和外部变量,具体取决于变量的声明位置和可见范围。

  1. 内部变量(局部变量): 内部变量是在函数内部或语句块内部声明的变量。它们只在声明它们的函数或语句块内可见,出了这个范围就无法访问。内部变量在函数或语句块执行时创建,随着函数或语句块的结束而销毁。在你的代码中,int i = 5; 的声明就是一个内部变量,它只在 main 函数内可见。

  2. (如果变量单独出现在括号中外部无法对其进行引用):局部变量和全局变量_第2张图片

  3. int main() {
        int i = 5; // 内部变量
        // ...
    }
    
  4. 外部变量(全局变量): 外部变量是在函数外部声明的变量,通常位于全局作用域中。外部变量在整个程序中都可见,可以被程序中的任何函数访问。在你的代码中,int i = 10; 的声明就是一个外部变量,它在整个程序范围内可见。

    int i = 10; // 外部变量
    
    void print(int a) {
        printf("I am print i=%d\n", i); // 访问外部变量
    }
    
    int main() {
        // ...
    }
    

    总结起来,内部变量是在局部作用域内声明的,只在局部范围内可见,而外部变量是在全局作用域内声明的,对整个程序可见。


    易错点(类型1——同名-就近原则)

局部变量与全局变量重命名——就近原则(实际获取和修改的值是局部变量的值)

经典错误:内部变量和外部变量重名(编译器不报错)内部变量的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。

  • 全局作用域(Global Scope): 全局作用域指的是在程序的任何地方都可见的范围。在全局作用域中声明的变量是全局变量,它们可以被程序中的任何函数访问。在你的代码中,int i = 10; 的声明是在全局作用域中,所以它是一个全局变量,可以被程序中的任何函数访问。
  • 局部作用域(Local Scope): 局部作用域指的是在函数或语句块内可见的范围。在局部作用域中声明的变量是局部变量,它们只能在声明它们的函数或语句块中访问。在你的代码中,int i = 5; 的声明是在 main 函数内部,所以它是一个局部变量,只能在 main 函数内部访问。

当在一个作用域内使用一个变量时,编程.语言首先会在当前作用域内查找是否有对应的局部变量,如果没有再向外部的父级作用域查找,直到找到该变量或者到达全局作用域。这就是所谓的就近原则(nearest enclosing scope rule)。


易错点(类型2——就近原则存在时的顺序问题)

注:就近原则存在就意味着局部变量与全局变量重命名

#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); //就近原则 就近于函数内部 函数内部出现同名局部变量 故就近于内部局部变量
}

第一处关于printf("main i=%d\n",i); 结果同外部变量一致:

就近原则(同名情况下才有)指的是在代码中从上到下的顺序中,离引用变量最近的那个变量会被选择。在 C 语言中,作用域是根据代码的结构来确定的,而变量的声明顺序以及作用域的嵌套关系都影响着就近原则。

代码中的全局变量 int i = 10; 的声明在 printf("main i=%d\n", i); 附近,因此就近原则会选择这个全局变量(执行顺序由上到下原则)

当你在某个作用域内引用一个变量时,编译器会从内向外查找该变量的声明,选择距离引用最近的那个声明。如果在当前作用域内没有找到声明,编译器会继续向上查找直到找到合适的声明或者到达全局作用域。

第二处print(3)和void  print(int i)

main函数中 调用函数的就近原则 是就近于函数内部 函数内部出现同名局部变量 故就近于内部局部变量结果为3

题中void print(int a) 换成了void  print(int i)

若未出现同名变量即仍是void print(int a) 则仍和全局变量保持一致 因为调用函数的就近原则 是就近于函数内部

易错点(类型3——正确命名局部变量-属于数据段中)

情形一:正确命名

#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. 测试: 单元测试和模块测试通常更容易应用于使用局部变量的函数,因为它们更容易理解和隔离。

全局变量在某些情况下可能是有用的,但在设计和编写代码时,通常更推荐使用局部变量和传递参数的方式,以提高代码的可读性、可维护性和安全性。

目前很多大厂也是不允许使用全局变量的 所以请记住:

不要使用全局变量!!! 不要使用全局变量!!! 不要使用全局变量!!!

你可能感兴趣的:(算法,c语言)