第 9 章 變數的生命期與使用範圍
變數可分成區域 (local 或 dynamic 或 block) 變數與全域 (global) 變數,其記憶體 的分配方式 與 時段 都不太相同,
於 第 9.1 節將介紹區域變數。
於 第 9.2 節將介紹全域變數。
於 第 9.3 節將介紹一些物件(辨識體)的區域性與全域性的關係。
於 第 9.4 節將介紹加上 static 修飾詞的變數與函數的性質。
本 章 主 要 內 容 如 下:
- 第 9.1 節 區域變數
- 第 9.2 節 全域變數
- 第 9.3 節 物件的使用範圍
- 第 9.4 節 static變數與函數
1. void f(int i) 2. { int j;.....} 3. void main() 4. {int a; 5. ..... 6. {int i;..... 7. } 8. f(a); 9. }
1. main() 2. { int i,j; 3. i=10; j=5; 4. { int i; 5. i=j++; 6. printf("i=%d,j=%dn",i,j); 7. } 8. printf("i=%d,j=%dn",i,j); 9. }
說明:
- main 含 2 個區域變數 i 及 j (以 i2, j2 表之,其中下標之 2 表示 變數定義於第 2 行),又於第 4 行 至第 7 行的 block 含一區域變數 i4。
- i2 的使用範圍為自第 2 行至第 9 行,扣除第 4 行至第 7 行,即自第 5 行 引用變數 i 是 i4而不是 i2。
- j2 的使用範圍為自第 2 行至第 9 行。
- i4 的使用範圍是自第 4 行至第 7 行。
- 程式執行完 第 5 行 i=j++; 後, i 的值為 5,即 i4 之值為 5, 但 i2 的值仍為 10。
- 執行完該程式的結果為
i=5,j=6 i=10,j=6
第 9.2 節 全域變數
在函數之外 宣告或定義 的變數都是 全域變數。全域變數 於程式編譯 之後就 存在一直到 程式的結束 才消失,其 使用範圍 為 自檔案的宣告或定義處 開始 至檔案的 結束,其名稱於 一個檔案 也必須是 唯一的。
全域變數的使用,其好處是 減少函數呼叫的 引數個數,其壞處是程式 較不易維修、除錯。
註:函數的呼叫其 side-effect (副作用)愈少愈好,即函數的呼叫 會改變 函數外 變數的值。 將於例 3 說明。
如果 區域變數 與 全域變數 同名,則 全域變數 的使用範圍就不包含 區域變數 的 使用範圍。
於例 3 將說明 全域變數 的上述性質。
例 3. 全域變數的使用範圍。
1. int s=0; 2. int square(int i) 3. { s=i+1; printf("s=%d,i=%dn",s,i); 4. return i*i; 5. } 6. int t=1; 7. main() 8. { int s=10; 9. t=square(s); 10. printf("s=%d,t=%dn",s,t); 11. }
第 9.3 節 物件的區域性與全域性
不僅變數的 宣告或定義 具有 區域性與全域性, 事實上任意一 辨識體(物件) 如 struct、 typedef、 enum、 巨集的宣告、 函數的定義等,其 使用範圍的規則 也相同。
C 程式 函數的定義不像 Pascal,函數 不能 定義在 另一個函數之內。因此,函數 都具有 全域性。 一般而言, 我們會宣告一個函數 在 檔頭或 在一個 block 的開頭,如:
例 4.
int square(int i); 或 main() main() { int square(int i); { int i=10,j=2; int i=10,j=2; j=square(i); j=square(i); } } int square() int square(int i) {return i*i;} {return i+i;}
#include< stdio.h > struct point {int x,y;}; struct rect {point topLeft, bottomRight}; int pointInRect(struct point, stuct rect); extern point currentLoc;
#include "file.txt" point currentLoc; int pointInRect(struct point p, stuct rect r) { int x1,x2,y1,y2; if(r.topLeft.x < r.bottomRight.x) { x1=r.topLeft.x; x2=r.bottomRight.x;} else { x2=r.topLeft.x; x1=r.bottomRight.x;} if(r.topLeft.y < r.bottomRight.y) { y1=r.topLeft.y; y2=r.bottomRight.y;} else { y2=r.topLeft.y; y1=r.bottomRight.y;} if(x1 <= p.x && p.x <= x2 && y1 <=p.y && p.y <= y2) return 1; else return 0; }
#include "file.txt" main() { struct rect r; r.topLeft.x=10; r.topLeft.y=10; r.bottomRight.x=20; r.bottomRight.y=20; scanf("%d %d", ¤tLoc.x, ¤tLoc.y); if(pointInRect(currentLoc,r)) printf("in the rectanglen"); else printf("not in the rectanglen"); }
說明:
- 檔案 file.c 含 全域變數 currentLoc 的定義。
- 檔案 file.txt 含全域變數 currentLoc 的宣告,即 extern point currentLoc, 其中 extern 表示 全域變數定義 於它處。
- 檔案 file.txt 含函數 pointInRect 的宣告,即 int pointInRect(struct point,struct rect);。
- 資料型態 struct point 及 struct rect 都宣告於檔案 file.txt 中, file.c 與 main.c 皆有 #include 指令 “file.txt”,因此可直接使用 struct point 及 struct rect。
第 9.4 節 static 變數與函數
區域變數的定義加上 static,其使用範圍與沒有加上 static 是沒有區別的, 但是其生命期就 如同 全域變數一樣,以下例來解說:
例 6.
int square(int i) { static int count=0; count++; return i*i; }
void Add(int n); void Mult(int n); int get();
#include "file.h" static int s=0; void Add(int n) {s=s+n;} void Mult(int n) {s=s*n;} int get(){return s;}
檔案 main.c 含
#include < stdio.h > #include "file.h" void main() {Add(5); Mult(10); printf("s=%dn",get()); }
說明:
- 檔案 file.c 含一 static 全域變數 s,該 變數 僅能於 file.c 引用。
- 檔案 main.c 不可加上 extern int s; 而引用變數 s。
- 程式執行的結果為
s=50
- C++ 程式 class 的設計方式 非常類似 file.c 與 file.h 的架構, 變數 s 就如同一個 private 的 data member。
一個函數的定義加上 static, 該 函數 也就變成 專屬該檔案 的函數, 其它檔案 就無法 呼叫該函數,於 C++ class 的設計,就好像一個 private 的 member function。回本章主目錄