作用範圍
變數是會失效的!如果有認真寫題目的人,應該會發現這一點。在之前的迴圈、陣列等也有提過區域變數與全域變數。不要將陣列宣告在 main 函式內,而是宣告於全域的其中一個理由就是:如果你的程式裡面需要用到函式,那這個寫在 main 函數外的函式就沒有辦法使用這個陣列裡的資訊了!那麼,現在就來看看,變數的作用範圍,大概是怎麼一回事吧!
最懶的判斷法
一個變數的作用範圍,自其宣告開始,到其所屬的右大括號為止
比如:
1 | int main(){ |
這個 a 的作用範圍,就是 main 函式結尾,而 b 與 c 的範圍,則到 for 迴圈結束為止。
有大括號的東西,例如 if、for、while、函式…… 都適用這個規則。並且不會因為省略大括號而有改變,也就是說,即使這樣:
1 | if(9 > 5) int b = 6; |
因為 if 只有一行而省略大括號,但變數 b 的作用範圍仍然只在這個 if 中。
1 | if(9 > 5) int b = 6; |
這樣是會 CE 的,因為在 cout 那行,這個 b 已經失效,是找不到 b 的。
更多範例
1 |
|
以上各變數的作用範圍,分別是哪裡呢?
答案:
- a : 3 ~ end
- b : 10 ~ 21
- c : 12 ~ 13
- d : 15 ~ 16
- e : 18 ~ 19
- f 是函式名稱,不是變數
- g : 6 ~ 7
這樣,對變數的作用範圍,有大致的了解了嗎?
接下來,我們就來看看,這樣會造成什麼問題。
重複宣告
一般來說,我們無法宣告具有相同名稱之變數,例如:
1 | int a = 5; |
這是一段會 CE 的程式碼。
但若作用範圍不同,則可以順利編譯執行。這會導致程式的執行結果與心中所想的不同,而且不太容易 debug。
1 |
|
輸出:
1 | 1 |
這段程式碼當中,總共出現了三種不同的 a,但因為他們作用範圍不同,因此不會有編譯錯誤。
大範圍的變數與小範圍的同時出現時,會優先以小的為主。因此在 11 行的 a 宣告後,雖然第 3 行的 a 仍在作用範圍,但在 11 行的 a 於 main 函式結尾失效前,都會暫時被覆蓋。在此期間,只要程式碼有提到 a,編譯器一律不會當成第 3 行的 a。
應盡量避免這樣的狀況發生,可於編譯指令中加上 -Wshadow 以自動偵測是否有變數同名。但仍建議平常在練習時養成變數命名的好習慣,勿隨意命名變數。
若只是用來代表目前迴圈跑到哪裡的 i, j, k 變數等,我會於迴圈的一開始宣告。這樣,兩個不同迴圈中的 i 才不會互相形成干擾。
練習
檢查自己過去的程式碼,有沒有重複命名的現象?是否曾因為重複命名而產生過 bug ?