0.前言
這個系列基本上是一月一更到兩月一更
今天寫一篇關於static的,內含大量乾貨,做好準備
1.基礎知識的回顧
1.1.記憶體的種類
一般來說,我們之前已經講過的變數(或者說是記憶體)可以大體分為這樣幾種:
- 全域性變數
- 區域性變數,也稱為自動變數
- 使用malloc分配的區域
- 常量、字串字面量
這裡回顧一下,在C++中,使用const宣告的常量是不可改變的,也就是在編譯期就確定下來了。因此,即使使用指標更改也不會實際修改到它的值。對於全域性變數,const出的值和字串字面量(即使用""括起來的字串),存在常量區,強制改變會使得程式異常退出。
1.2.作用域和生命週期
對於全域性變數,它由始至終都是存在的,作用域是全部。
區域性變數的作用域和宣告週期僅存在一個函式中,當函式返回,它就會從棧中銷燬。
使用malloc分配的記憶體區域,它的生命週期一直到呼叫free為止。
對於字串字面量和常量,它的作用域和宣告週期與全域性變數和區域性變數類似。
2.static的相關用法
2.1.靜態變數的定義
我們把使用static修飾的變數和全域性變數統稱為靜態變數。
靜態變數,顧名思義,就是可以貫穿整個程式執行的時間內的變數。
2.2.static的地址
我們來寫一段程式碼,進行一個實驗:
#include<iostream>
#include<windows.h>
using namespace std;
int a;//全域性變數
static int b;//全域性static變數
void f(void){
static int c;//定義在函式內的static變數
printf("c..%p\n",&c);
}
int main(){
printf("a..%p\n",&a);
printf("b..%p\n",&b);
f();
return 0;
}
(注:今天我換了一臺電腦進行編輯,使用的是codeblocks來編輯,編譯器我設定的是VC)
輸出的結果如下
可以看到,static修飾的變數,與全域性變數的地址是接近的,可以證明它是在全域性儲存區。
2.3.函式體內的static
還是以例子來說明,這樣比較好理解。假如我們寫一個將數字轉為字串的函式:
#include<iostream>
#include<windows.h>
using namespace std;
char *toint(int x){
char s[1000];
sprintf(s,"%d",x);
return s;
}
int main(){
char s[1000],t[1000];
strcpy(s,toint(8));
strcpy(t,toint(10));
printf("%s\n%s\n",s,t);
return 0;
}
使用sprintf函式,進行字串間的轉換。
這段程式碼,乍一看似乎沒有問題,而且在我的環境還可以正常執行:(部分環境會Segmentation Fault,就更加能說明這個問題)
但是我們仔細看看,畫面下方報出了一行警告:
(看我選中的一條,上面一條似乎是環境沒有配置到位,先不管了)
這是因為,其中的s陣列是區域性變數,或者說是自動變數,儲存在棧中,在函式返回之後,這個地址就不能再使用了,因為這個陣列已經銷燬了,s地址所在的地方是“無人區”,訪問時就有可能訪問到不該訪問的資料,進而出錯。
對於這一類的問題,解決方法有使用malloc和new來分配記憶體,這樣可以在free之前多次使用:
char *toint(int x){
char *s=new char [1000];
sprintf(s,"%d",x);
return s;
}
這一次沒有報錯。
事實上,還可以使用靜態變數來解決(不過靜態變數主要的用途不在這裡),這樣這個記憶體就不會在返回的時候被釋放。
char *toint(int x){
static char s[1000];
sprintf(s,"%d",x);
return s;
}
同樣沒有報錯。
3.static的更多特性與用途
3.1.在函式退出後,static變數的值保持不變
#include<iostream>
#include<windows.h>
using namespace std;
void f(){
static int Count;
printf("%d\n",Count);
Count++;
}
int main(){
for(int i=0;i<10;i++){
f();
}
}
由於static的變數一直在同一個儲存區,因此可以發現,退出函式時,static變數的值保持不變,輸出結果為:
3.2.多檔案中的使用
static的變數,只能在當前的檔案內進行訪問。
//a.cpp
static int x;
int main(){
x=100;
cout<<x<<endl;
f();
}
//b.cpp
extern int x;
void f(){
cout<<x<<endl;
}
在b.cpp中,無法訪問a.cpp中的x變數,因為x是使用static修飾的(即使使用了extern進行宣告)
包括函式也可以使用static進行修飾:
static int f();
關於更多的內容,敬請期待:
【原創】淺談指標(十三)關於static(下)
(預計5月釋出)