C/C++学习笔记:变量的作用域和变量的引用

作用域

所谓作用域(Scope),就是变量的有效范围,就是变量可以在哪个范围以内使用。有些变量可以在所有代码文件中使用,有些变量只能在当前的文件中使用,有些变量只能在函数内部使用,有些变量只能在 for 循环内部使用。

变量的作用域由变量的定义位置决定,在不同位置定义的变量,它的作用域是不一样的。本节我们只讲解两种变量,一种是只能在函数内部使用的变量(局部变量),另一种是可以在所有代码文件中使用的变量(全局变量)

局部变量

函数内部定义的变量,它的作用域也仅限于函数内部,出了函数就不能使用了,我们将这样的变量称为局部变量(Local Variable)。函数的形参也是局部变量,也只能在函数内部使用。

对局部变量的两点说明:

  • main() 也是一个函数,在 main() 内部定义的变量也是局部变量,只能在 main() 函数内部使用。
  • 形参也是局部变量,将实参传递给形参的过程,就是用实参给局部变量赋值的过程,它和a=b; sum=m+n;这样的赋值没有什么区别。
全局变量

C语言允许在所有函数的外部定义变量,这样的变量称为全局变量(Global Variable)。

全局变量的默认作用域是整个程序,也就是所有的代码文件,包括源文件(.c文件)和头文件(.h文件)。如果给全局变量加上 static 关键字,它的作用域就变成了当前文件,在其它文件中就无效了。

#include <stdio.h>
//定义三个全局变量,分别表示三个面的面积
int s1 = 0, s2 = 0, s3 = 0;
int vs(int length, int width, int height){
    int v;  //体积
    v = length * width * height;
    s1 = length * width;
    s2 = width * height;
    s3 = length * height;
    return v;
}
int main(){
    int v = 0;
    v = vs(15, 20, 30);
    printf("v=%d, s1=%d, s2=%d, s3=%d\n", v, s1, s2, s3);
    v = vs(5, 17, 8);
    printf("v=%d, s1=%d, s2=%d, s3=%d\n", v, s1, s2, s3);
    return 0;
}

运行结果:
v=9000, s1=300, s2=600, s3=450
v=680, s1=85, s2=136, s3=40

根据题意,我们希望借助一个函数得到四份数据:体积 v 以及三个面的面积 s1、s2、s3。遗憾的是,C语言中的函数只能有一个返回值,我们只能将其中的一份数据(也就是体积 v)放到返回值中,其它三份数据(也就是面积 s1、s2、s3)只能保存到全局变量中。

C语言代码从前往后依次执行,变量在使用之前必须定义或者声明,全局变量 s1、s2、s3 定义在程序开头,所以在 vs() 和 main() 中都有效。

在 vs() 中将求得的面积放到 s1、s2、s3 中,在 main() 中能够顺利取得它们的值,这说明:在一个函数内部修改全局变量的值会影响其它函数,全局变量的值在函数内部被修改后并不会自动恢复,它会一直保留该值,直到下次被修改。

全局变量也是变量,变量只能保存一份数据,一旦数据被修改了,原来的数据就被冲刷掉了,再也无法恢复了,所以不管是全局变量还是局部变量,一旦它的值被修改,这种影响都会一直持续下去,直到再次被修改。

全局作用域运算符::
#include <iostream>
using namespace std;
int a=10; //全局变量
int main(){
    int a=5;
    cout << a <<endl;
}

此处,main()中的局部变量屏蔽了全局变量,输出结果是5.

如果想要在main() 函数内部输出全局变量的值,可以使用 :: 来解除屏蔽。

#include <iostream>
using namespace std;
int a=10; //全局变量
int main(){
    int a=5;
    cout << a <<endl;
    cout << ::a <<endl;
}

输出

5
10
综合示例
#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,但它们的作用域不同,在内存中的位置(地址)也不同,所以是相互独立的变量,互不影响,不会产生重复定义(Redefinition)错误。

  1. 对于 func1(),输出结果为 20,显然使用的是函数内部的 n,而不是外部的 n;func2() 也是相同的情况。

当全局变量和局部变量同名时,在局部范围内全局变量被“屏蔽”,不再起作用。或者说,变量的使用遵循就近原则,如果在当前作用域中存在同名变量,就不会向更大的作用域中去寻找变量。

2) func3() 输出 10,使用的是全局变量,因为在 func3() 函数中不存在局部变量 n,所以编译器只能到函数外部,也就是全局作用域中去寻找变量 n。

注意func3()虽然在main()中被调用,但其与main()平级,其外部作用域均为全局作用域。

  1. { }包围的代码块也拥有独立的作用域,printf() 使用它自己内部的变量 n,输出 40。

  2. C语言规定,只能从小的作用域向大的作用域中去寻找变量,而不能反过来,使用更小的作用域中的变量。对于 main() 函数,即使代码块中的 n 离输出语句更近,但它仍然会使用 main() 函数开头定义的 n,所以输出结果是 30。

变量的引用&

引用是一个别名,也就是说,它是某个已存在变量的另一个名字。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
using namespace std;
int main(){
    int a=10;
    int &b=a; //声明:b为a的引用
    cout << "a= " << a << " ,b= " << b << endl;
    a=5;
    cout << "a= " << a << " ,b= " << b << endl;
    b=100;
    cout << "a= " << a << " ,b= " << b << endl;
    //输出a,b的地址
    cout << &a << " ," << &b << endl;
    return 0;
}

运行结果

在这里插入图片描述

注意:

  • 由上面的例子可以看出,变量和其引用变量的值会相互影响。
  • 由上面的例子可以看出,变量和其引用共享同一块内存,有相同的地址
  • 引用不是一种独立的数据类型,必须依附于一种已有的数据类型(int,float…)
    • 不能建立 void 类型的引用。
C++ 引用 vs 指针

引用很容易与指针混淆:

  • 不存在空引用。引用必须连接到一块合法的内存。

  • 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象

    如下列做法都是错误的

    int a1,a2;
    int &b=a1;
    int &b=a2;//错误,b已经是a1的别名了,不能更改
    
  • 可以将变量的引用的地址赋值给一个指针

    int a=3;
    int &b=a;
    int *p=&b;//指针p指向b,b是a的别名;相当于指针p指向a,合理
    
  • 相同点:引用和指针都要在创建时对其进行初始化。
区分取地址&和引用&

&a 前面有数据类型时 (如 int &a) 必然是对引用的声明,如果没有数据类型 p=&a ,则为取地址运算符。

&引用作为函数参数
  • 按值传递函数参数,在函数内部处理形参,无法改变传入的实参的值;
  • 按指针和按引用传递函数参数,在函数内部处理形参,可以改变传入的实参的值;
  • 按引用传递比按指针传递更直观。

下面的例子:

第3行,声明swap函数时,形参列表中的 a,b 是整型变量的引用,但此时并未初始化

第7行,main函数调用swap时,由实参 i , j 把变量名传递给形参,这样 a, b 就分别成为了 i, j的别名;a, i共享同一块内存,所以在swap内改变 a, 会影响 i 的值。

#include <iostream>
using namespace std;
void swap(int &a ,int &b);
int main()
{
	int i =3,j = 5;
    swap(i,j);
    cout<<"i="<<i<<endl<<"j="<<j<<endl;
    getchar();
    return 0;
}

void swap(int &a,int &b)
{
    int temp;
    temp = a;
    a =b;
    b= temp;
}

运行结果:

i = 5
j = 3
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值