區域全域靜態變數
區域變數與全域變數
在函式之外的變數是全域變數,整個程序都能使用它。
在函式之內的變數是區域變數,存取範圍就是在該函式之中。
函式中的區域變數
若全域變數與函式內的區域變數相同,就近原則,使用最近的區域變數。
區域變數會跟著函式呼叫完畢,被記憶體回收(記憶體釋放)。
以下的程式碼,func()與main()函式有區域變數n,印出區域變數n。
test()沒有區域變數n,存取全域變數。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 全域
int n = 10;
void func() {
// 區域n
int n = 20;
cout << "func n =" << n << endl;
}
void test() {
// 函式沒定義區域變數n,使用全域n
cout << "test n = " << n << endl;
}
int main() {
// 區域n
int n = 30;
func();
test();
cout << "main n =" << n << endl;
return 0;
}
func n =20
test n = 10
main n =30
Block程式碼區塊中區域變數
func()函式有定義區域變數n,程式碼區塊中也有定義區域變數n。
就近原則,會使用程式碼區塊中的n。
1
2
3
4
5
6
7
8
9
10
11
12
int n = 10;
void func() {
int n = 20;
{
int n = 55;
cout << "func n =" << n << endl;
}
}
int main() {
func();
return 0;
}
func n =55
for(int n = 1) {} 程式碼區塊,n是for程式碼區塊的區域變數。
就近原則,使用for()定義的區域變數n。
1
2
3
4
5
6
7
8
9
10
11
int n = 10;
void func() {
int n = 20;
for(int n = 1; n <10 ;n++) {
cout << n << endl;
}
}
int main() {
func();
return 0;
}
1
2
3
4
5
6
7
8
9
if(1) {} 程式碼區塊也是相同道理,就近原則。
1
2
3
4
5
6
7
8
9
10
11
12
int n = 10;
void func(int n) {
if (1) {
int n = 100;
cout << "func n= " << n << endl;
}
}
int main() {
int n = 55;
func(n);
return 0;
}
func n= 100
函式參數
函式參數也是區域變數,存取範圍只有在函式中,不可以超出函式的範圍之外。
以下程式碼func()函式有修改main()傳入的n變數,但對func而言,是把main的n變數中的值,拷貝到func()中的區域變數n的值中,修改func()函式的n變數不會影嚮main()的n變數。
請參考函式參數傳遞文章。
1
2
3
4
5
6
7
8
9
10
11
int n = 10;
void func(int n) {
n++;
cout << "func n= " << n << endl;
}
int main() {
int n = 66;
func(n);
cout << "main n = " << n << endl;
return 0;
}
func n= 67
main n = 66
預設值
全域變數與全域陣列都會有預設值。
型態 | 預設值 |
int | 0 |
char | \0 |
float | 0.0 |
double | 0.0 |
指標類型 | NULL |
區域變數與全域變數預設值
函式內的區域變數如果不設初始值,會是亂七八糟的值。
函式外的全域變數會使用預設值,如int就會是0,char就會是\0
。
所以區域變數要memset,清空亂七八糟的值。
1
2
3
4
5
6
7
8
9
10
int n;
void func() {
int n;
cout << "func n = " << n << endl;
}
int main() {
func();
cout << "main n = " << n << endl;
return 0;
}
func n = 32759
main n = 0
區域陣列預設值
區域陣列的值,也是亂七八糟的值,使用時要memset。
全域陣列,系統會給預設值,若是int,預設值為0。
1
2
3
4
5
6
7
8
9
10
11
void func() {
int arr[5];
int len = sizeof(arr) / sizeof(int);
for (int i = 0; i < len; i++) {
cout << arr[i] << endl;
}
}
int main() {
func();
return 0;
}
0
0
0
0
-1074793232
區域全域變數 Memory Layout
下圖中,區域變數都在Statck。
靜態變數
函式中靜態變數
函式中的靜態變數是共享變數,不會跟著函式被系統銷毀。
func()中的靜態變數n,除了第一次呼叫func()函式會執行初始化。
static int n = 10;
第二次呼叫func()函式,就不會執行初始化。
靜態變數是存放在bss segment、data segment中,查上一個Memory Layout圖。
1
2
3
4
5
6
7
8
9
10
11
void func() {
static int n = 10;
n++;
cout << "func n = " << n << endl;
}
int main() {
func();
func();
func();
return 0;
}
func n = 11
func n = 12
func n = 13
區域變數
一對花括號{}
包起來的就是程式碼區塊(block)或函式主體(Body)。程式碼區塊可以是if (){}或while(){}的程式碼區塊,但這篇要探討的是只有花括號{}
包起來的程式碼區塊。
1
2
3
4
5
6
7
8
9
int main() {
int var11 = 100;
{
int var11 = 10;
cout << "inner var11 = " << var11 << endl;
}
cout << "outer var11 = " << var11 << endl;
return 0;
}
執行結果
inner var11 = 10
outer var11 = 100
- 第3行至第6行
在程式碼區塊中{}
,所定義的變數都是區域變數,離開{}
區塊就不能再讀取了,因為{}
區塊中的區域變數已經被系統回收掉。可以想像{}
就像是函式一樣。在函式中,函式中定義的變數都是區域變數,離開函式就不能被外部讀取區域變數,因為區域變數已經被系統回收了。
程式碼區塊
在{}
區塊中,可以讀取程式碼區塊外的變數
1
2
3
4
5
6
7
8
9
10
11
12
int main() {
int var11 = 100;
int var12 = 200;
{
int var11 = 10;
cout << "inner var11 = " << var11 << endl;
//在`{}`區塊中,可以程式碼區塊外的變數
cout << "inner var12 = " << var12 << endl;
}
cout << "outer var11 = " << var11 << endl;
return 0;
}
執行結果
inner var11 = 10
inner var12 = 200
outer var11 = 100
在程式區塊中{}
無法讀取同名的區塊外的變數
因為在{}
區塊中,同名的區塊外變數會先被暫時隱藏,直到程式執行時離開{}
區塊,區塊內的區域變數被系統回收掉,同名的變數就會將記憶體位置指向區塊外變數。
程式區塊中{}
讀取跟區域變數同名的全域變數
使用::可以讀取全域變數。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//定義全域變數var11
int var11 = 100;
int main() {
//定義區域變數var11
int var12 = 200;
{
//印出區域變數var11
int var11 = 10;
cout << "inner var11 = " << var11 << endl;
cout << "inner var12 = " << var12 << endl;
//印出全域變數var11
cout << "outer var11 = " << ::var11 << endl;
}
return 0;
}
執行結果
inner var11 = 10
inner var12 = 200
outer var11 = 100
for程式區塊中的區域變數
變數i的有效範圍,只有在{}
程式區塊中,離開{}
程式區塊,區域變數i就無法在外部讀取。
1
2
3
for (int i = 0; i < 10; i++) {
}
若要變數i也可以在外部使用,可把變數i放在外部。
1
2
3
4
int i = 0;
for (; i < 10; i++) {
}
cout << "i = " << i << endl;
執行結果
i = 10
虛擬碼
可以在程式區塊寫虛擬碼,進行驗證,作為之後正式的函式使用。 以下程式碼是在寫參數為指標,將指標宣告記憶體空間。
1
2
3
4
5
6
7
8
9
10
11
12
int main() {
//宣告指標
int* p = 0;//0就是nullptr 代表沒有指向任何記憶空間
{
int** pp = &p;//存放指標的位址,要用雙指標
*pp = new int(3);//雙指標取值,並動態配置記憶體空間
}
//印出p指標的位址,去p指標的記憶體位址取值,並印出來
cout << "p=" << p << ",*p=" << *p << endl;
return 0;
}
第6行,去雙指標pp的記憶體位址取值,取出來是p的指標記憶體位址,使用new來分配動態配置記憶體空間,並且設值”3”,動態配置完成會傳回記憶體位址,由指標去存位址。
執行結果
p=0x60000000c000,*p=3
虛擬碼執行成功後,將{}
程式碼區塊移到main()函式之外,並宣告成函式。
1
2
3
4
5
6
7
8
9
10
11
void initMemory(int** pp) //存放指標的位址,要用雙指標
{
*pp = new int(3);//雙指標取值,並動態配置記憶體空間
}
int main() {
//宣告指標
int* p = 0;//0就是nullptr 代表沒有指向任何記憶空間
initMemory(&p);//指標的位址傳入函式。
cout << "p=" << p << ",*p=" << *p << endl;
return 0;
}
執行結果
p=0x600000008030,*p=3