跳至正文
View Categories

5 min read

1. 作用域 #

1.1 什么是作用域 #

这里有一段例程,请编译运行。并说明,在编译的时候,遇到了什么问题。

#include <iostream>
using namespace std;
int main()
{
    if(true)
    {
        int a(79);
    }
    cout << "a = " << a << endl;
    return 0;
}

可以看到,编译器提示:a 没有定义
这是为什么呢?

在 C++ 中,变量 a 定义 if 的 {} 内,所以在超过 {} 的区域,a 是不存在的!
这里 if 的 {} 区域,就被称为 a 的“作用域”

其实,说白了,所谓的变量 a 的 “作用域”,就是变量 a 可以被识别,被使用的区域。

C++ 中规定,作用域主要是由大括号“{ }”确定的。
变量在作用域内才是有效的。
运行到作用域结束时,变量就会被彻底删除。

1.2 变量的作用域 #

1.2.1 大括号 #

请看下面的代码:

#include <iostream>
using namespace std;
int main()
{
    {
        int a(79); // 从定义 a 这行开始,到大括号结束,都属于 a 的作用域;
        int b(79); // 从定义 b 这行开始,到大括号结束,都属于 b 的作用域;
        int c(79); // 从定义 c 这行开始,到大括号结束,都属于 c 的作用域;
    }

    cout << "a = " << a << endl; // 这里不属于 a 的作用域。

    return 0;
}

在 C++ 程序中,大括号可以直接框定一个封闭的区域。
在这个区域内定义的变量,在这个区域之外,不可使用。

这是一个很有用的功能。

  • 复用代码,解决“变量重复定义”的编译错误。
// 此代码是有问题的,“变量 a 重复定义”。
#include <iostream>
using namespace std;
int main()
{
    int a(79); 
    cout << "a = " << a << endl;

    int a(80); 
    cout << "a = " << a << endl;

    int a(81); 
    cout << "a = " << a << endl;

    return 0;
}

加上大括号,就可以解决上面的问题。

// 此代码是正确的。
#include <iostream>
using namespace std;
int main()
{
    {
        int a(79); 
        cout << "a = " << a << endl;
    }

    {
        int a(80); 
        cout << "a = " << a << endl;
    }

    {
        int a(81); 
        cout << "a = " << a << endl;
    }

    return 0;
}

1.2.2 if 的大括号 #

其实所谓 if 的作用域,本质还是看大括号的范围。

#include &lt; iostream &gt;
using namespace std;
int main()
{
    if(true)
    {
        int a(79); // 从定义 a 这行开始,到大括号结束,都属于 a 的作用域;
        int b(79); // 从定义 b 这行开始,到大括号结束,都属于 b 的作用域;
        int c(79); // 从定义 c 这行开始,到大括号结束,都属于 c 的作用域;
    }
    cout << "a = " << a << endl;  // 这里不属于 a 的作用域。

    if(true)
        int a(79); // 只有这一行,都属于 a 的作用域;
                   // 这一行开始,已经不属于 a 的作用域;
                   // 而且,这里的 a 和 上面的 a 不是同一个变量,请解释为什么。

    return 0;
}

答案:
两个变量虽然都叫做 a ,但是属于不同的作用域。当上面的 a 在执行到作用域边缘时,
这个 a 就会被“释放”,也就是“从程序中删除”,这个变量 a 就不再存在了。
当执行到下面的 a 时,新创建的 a 是一个完全不同于之前的新变量。

1.2.3 while 的大括号 #

其实所谓 while 的作用域,本质还是看大括号的范围。

#include <iostream>
using namespace std;
int main()
{
    while(true)
    {
        int a(79); // 从定义 a 这行开始,到大括号结束,都属于 a 的作用域;
        int b(79); // 从定义 b 这行开始,到大括号结束,都属于 b 的作用域;
        int c(79); // 从定义 c 这行开始,到大括号结束,都属于 c 的作用域;
        break;
    }
    cout << "a = " << a << endl;      // 这里不属于 a 的作用域。
       
    while(true)
        int a(79); // 只有这一行,都属于 a 的作用域;
                   // 这一行开始,已经不属于 a 的作用域;
                   // 而且,这里的 a 和 上面的 a 不是同一个变量,原因同上。

    return 0;
}

1.3 作用域的嵌套 #

所谓的作用域嵌套,其实我们一点都不陌生。

#include <iostream>
using namespace std;
int main()
{
    int a(10);
    if(a > 5)
    {
        cout << "Hello World!";
    }

    return 0;
}

这里的 main 的 {} 中,嵌套了 if 的 {}。
这就是作用域的嵌套。

我们来看一个比较特别的例子。

#include <iostream>
using namespace std;

int global_value(0);

int main()
{
    int a(10);
    global_value = 50;

    if(a > 5)
    {
        int a2(12);
        cout << "Hello World! global_value = " << global_value;
    }

    return 0;
}

这里,可以划分为 3 个作用域。
1. global_value 的作用域:main 以外的区域,从变量定义到程序末尾(注意,定义之前不属于作用域)。
2. a 的作用域:从变量定义到 main 大括号的末尾(注意,定义之前不属于作用域)。
3. a2 的作用域:从变量定义到 if 大括号的末尾(注意,定义之前不属于作用域)。
嵌套关系:
1 包含 2,2 包含 3。

1.4 大作用域和小作用域 #

1.4.1 划分 #

所以,很明显,1 和 2 相比,1 是大作用域,2 是小作用域。

1.4.2 同名变量 #

下面,对上述的程序做一些修改。

#include <iostream>
using namespace std;

int a(0);                    // A 行,a 的值为 0

int main()
{
    int a(10);               // B 行,a 的值为 10
    a = 50;                  // C 行,a 的值为 50

    if(a > 5)
    {
        int a(12);           // D 行,a 的值为 12
        cout << "a = " << a;           // E 行,a 的值为 12,【注意】,最小作用域的 a 的值为 12
    }

    return 0;                      // F 行,a 的值为 50,【注意】,值为 12 的那个 a 已经被释放了。
}
                                   // G 行,a 的值为 0, 【注意】,值为 50 的那个 a 已经被释放了。
                                   // main 之外的区域,是有作用的,将在后续介绍。

这是一个很极端的例子。大家在平时的编程中,一定不要这样去写。

这里的 A B D 行,定义了 3 个变量 a。
首先,这三处定义,所定义的 3 个变量 a 是不同的。
在之前的学习中,我们说过,变量的作用域结束时,变量会被释放。
所以,
G 行:只有 A 行定义的 a 存在。
D 行:存在 A B D 行,定义的 3 个变量 a。
B 行:存在 A B 行,定义的 2 个变量 a。
下面就各个作用域内变量 a 的值,做一些说明:
if 区域内:存在 A B D 行,定义的 3 个变量 a,最小作用域上的变量起作用。
main 区域内:存在 A B 行,定义的 2 个变量 a,最小作用域上的变量起作用。
main 区域外:存在 A 行,定义的 1 个变量 a,最小作用域上的变量起作用。
所以,遇到同名的变量时,分析代码需要先确定它们的作用域。
这些变量虽然名字相同,其实它们本质上都是不同的变量
一定不能将它们看作相同的变量。

最后将上述代码修改如下,请结合上面的代码,阅读并理解。

#include <iostream>
using namespace std;

int a_0(0);                    // A 行,a 的值为 0

int main()
{
    int a_1(10);               // B 行,a 的值为 10
    a_1 = 50;                  // C 行,a 的值为 50

    if(a_1 > 5)
    {
        int a_2(12);           // D 行,a 的值为 12
        cout << "a = " << a_2;           // E 行,a 的值为 12
    }

    return 0;                      // F 行,a 的值为 50,【注意】,a_2 已经被释放了。
}
                                   // G 行,a 的值为 0, 【注意】,a_1 已经被释放了。

2. 回顾 while 循环 #

小练习:
请用 while 写一个 10 次的循环。

// 写法一
int i(0);
while(true)
{
    i++;
    cout << i;
    if(i > 10)
        break;
}

// 写法二
int i(0);
while(i < 10)
{
    i++;
    cout << i;
}

除了 while 可以表示循环外,C++ 还支持一个循环的语句,叫做 for

3. for 循环 #

我们先来改写一下上的代码。

#include <iostream>
using namespace std;
int main()
{
    for(int i = 0; i < 10; i++) // 使用 for 完成 10 次循环
    {
        cout << i;
    }
    return 0;
}

下面我们来看一下 for 循环的基本结构。

3.1 基本结构 #

for(语句一; 语句二; 语句三) // 使用 for 完成 10 次循环
{
    // 循环体
}
  • 语句1,语句2,语句3 之间,要使用 分号 间隔;

3.2 执行过程 #

了解了 for 循环的执行过程,请回答下面的问题。

#include <iostream>
using namespace std;
int main()
{
    for(int i = 0; i < 10; i++) // 请问:当循环结束时,i 的值是多少?(注意:不是输出的值)
    {
        cout << i;
    }
    return 0;
}

答案:

i=10;

请看下面代码

#include <iostream>
using namespace std;
int main()
{
    for(int i = 0; i < 10; i++) 
    {
        cout << i;
    }
    cout << i;       // 请问:这里属于 i 的作用域吗?
    return 0;
}

答案:

并不属于。
这里请特别注意,i 是定义在 for 循环的“语句一”处。
i 的作用域限制在 for 循环的范围之内。


for(int i = 0; i < 10; i++)   // 属于 i 的作用域
{                           // 属于 i 的作用域
    cout << i;              // 属于 i 的作用域
}                           // 属于 i 的作用域
cout << i;                  // 【不】属于 i 的作用域


for(int i = 0; i < 20; i++)   // 这是一个全新的变量 i
{
    cout << i;
}

4. 课后练习 #

请用for循环完成练习

  1. 编程求解1+3+5+…+n
  2. 寻找雷劈数
  3. 与7无关的数
  4. 求平均年龄