3.8 變數範圍(Scope)
當程式變大時,變數會越來越多。我們需要理解每個變數在程式的哪個地方可以被使用。這就是變數範圍(Scope)的概念。
區塊(Block)
在 C++ 中,大括號 {} 圍起來的區域稱為一個區塊。每個區塊有自己的作用域。
{
// 這是一個區塊
int x = 5; // x 在這個區塊內宣告
cout << x; // 在這裡可以使用 x
}
// 這裡無法使用 x(超出了它的作用域)
作用域規則
- 變數只能在它被宣告的區塊以及更深層的巢狀區塊內使用
- 離開宣告它的區塊後,變數自動銷毀——意思是出了區塊,這個變數名稱就不能再用了(想用就得重新宣告)
¶範例程式碼:作用域示意
#include <iostream>
using namespace std;
int main() { // main 函式的區塊開始
int x = 10; // 在 main 區塊宣告 x
cout << "outer x: " << x << endl; // 輸出:10
if (x > 5) { // if 的區塊開始
int y = 20; // 在 if 區塊宣告 y
cout << "inner y: " << y << endl; // 輸出:20
cout << "inner sees x: " << x << endl; // 輸出:10
} // if 區塊結束,y 銷毀
// cout << y << endl; // ✗ 編譯錯誤:y 超出作用域
cout << "outer still has x: " << x << endl; // ✓ 輸出:10
return 0;
}
執行結果
outer x: 10
inner y: 20
inner sees x: 10
outer still has x: 10
¶同一個區塊不能重複宣告同名變數
如果在同一個區塊裡宣告兩個同名變數,編譯器會直接報錯:
int x = 5;
int x = 10; // ✗ 編譯錯誤:redeclaration of 'int x'
看到 error: redeclaration of ...,就是同一個區塊裡把同一個名字宣告了兩次——改名,或刪掉其中一個宣告。
那如果是不同層的區塊宣告同名變數呢?這就是接下來的「變數遮蔽」。
¶變數遮蔽(Variable Shadow)
如果在內層區塊宣告一個和外層同名的變數,這是合法的,但內層的變數會「遮蔽」(隱藏)外層的變數。這很容易造成 bug。
#include <iostream>
using namespace std;
int main() {
int x = 10; // 外層的 x
cout << "outer x: " << x << endl; // 輸出:10
{
int x = 20; // ✗ 內層的 x(同名,遮蔽了外層的 x)
cout << "inner x: " << x << endl; // 輸出:20
}
cout << "outer x: " << x << endl; // 輸出:10(外層 x 沒變)
return 0;
}
執行結果
outer x: 10
inner x: 20
outer x: 10
細節:區域變數從「宣告的那一行」才開始存在
內層那個同名變數,並不是一進區塊就生效,而是從它被宣告的那一行起才算數。在那行之前用到同一個名字,指的仍然是外層的變數:
int x = 10; // 外層 x
{
x = 2; // 這行還沒宣告內層 x → 改到的是「外層」的 x
int x = 5; // 從這行起,x 才變成內層的變數
cout << x; // 輸出:5(內層 x)
}
cout << x; // 輸出:2(外層 x 剛剛被改成 2 了)
所以「先用、後宣告」同一個名字時,前後其實動到兩個不同的變數——很容易看走眼。(全域變數也一樣:函式裡在宣告同名區域變數之前用到那個名字,改的是全域的那個。)
¶全域變數(Global Variables)
如果在所有函式外(也就是 main 之外——main 本身就是一個函式)宣告變數,它就是全域變數,可以在任何地方使用(但這通常不是好習慣):
#include <iostream>
using namespace std;
int global_x = 100; // 全域變數
int main() {
cout << global_x << endl; // 可以使用
return 0;
}
¶生命週期與宣告位置建議
變數從宣告的那一行誕生,到離開它所在的區塊時銷毀——這段期間稱為它的生命週期(lifetime)。
那實務上該把變數宣告在哪裡?兩個建議:
- 在第一次用到的地方宣告,宣告時就初始化。變數活得越短,越不容易被不相關的程式碼改壞;Google 的 C++ 風格指南也是同樣的建議。
- 需要「一直記住東西」的變數,宣告在夠外層的區塊。例如第四單元會遇到:累加總和的變數若宣告在迴圈裡面,每一圈都會重新誕生、重新初始化,前面累加的結果就全丟了——這種要跨迴圈保留的變數,必須宣告在迴圈外。
延伸閱讀:Google C++ 風格指南:區域變數(中文版)
¶動手試試看
寫一個程式,在 main 函式中宣告 x = 5,然後在一個 if 區塊內宣告另一個 x = 10。輸出兩層的 x,驗證遮蔽的效果。然後,修改程式使用不同的變數名,看清楚之後程式更容易理解。