全局变量、静态全局变量、静态局部变量和局部变量的区别
static和const都是C++中比較麻煩的東西,只要是太容易混淆他們的作用,之前對static做過點總結,但是不全面,還有很多小的錯誤,現在整理一下:
變量可以分為:全局變量、靜態全局變量、靜態局部變量和局部變量。
------------------------------------------------------------------------------------
『維基百科』給出如下定義
“靜態變量”這一術語有兩個容易混淆的定義:
而在以Pascal為代表的許多程序語言中,所有局部變量都由系統自動分配存儲空間,而所有全局變量的存儲空間則以靜態分配的方式獲取(對應“靜態變量”),因此由于實際上“局部變量”和“全局變量”這兩個術語已足以涵蓋所有的情況,在這些程序語言中通常不使用“靜態變量”這一術語,而直接以“全局變量”代之。一般來說,在這些程序語言中,靜態變量就是全局變量,而即使在有明確區分全局和靜態變量的程序語言中,在編譯后的代碼里二者也以相同的方式獲取存儲空間。而今術語“靜態變量”的概念則主要基于C族語言的“static”的定義。
------------------------------------------------------------------------------------
按存儲區域分,全局變量、靜態全局變量和靜態局部變量都存放在內存的靜態存儲區域,局部變量存放在內存的棧區。
按作用域分,全局變量在整個工程文件內都有效;靜態全局變量只在定義它的文件內有效;靜態局部變量只在定義它的函數內有效,只是程序僅分配一次內存,函數返回后,該變量不會消失;局部變量在定義它的函數內有效,但是函數返回后失效。
通常,static的使用在三個方面:
(1)靜態局部變量?????????????? (C語言)
(2)外部靜態變量/函數?????? (C語言)
(3)靜態成員變量/函數?????? (C++語言_類)
一.靜態局部變量(一般定義在函數內部):
該情況下又可以分為三種功能:
a:隱藏
代碼0:下面是a.C的內容:
char a = 'A'; // global variablevoid msg(){printf("Hello\n");}?下面是main.C的內容:
int main(void){extern char a; // extern variable must be declared before useprintf("%c ", a);(void)msg();return 0;}?程序的運行結果是:
?A Hello
?????你可能會問:為什么在a.c中定義的全局變量a和函數msg能在main.c中使用?前面說過,所有未加static前綴的全局變量和函數都具有全局可見性,其它的源文件也能訪問。此例中,a是全局變量,msg是函數,并且都沒有加static前綴,因此對于另外的源文件main.c是可見的。
如果加了static,就會對其它源文件隱藏。例如在a和msg的定義前加上static,main.c就看不到它們了。利用這一特性可以在不同的文件中定義同名函數和同名變量,而不必擔心命名沖突。Static可以用作函數和變量的前綴,對于函數來講,static的作用僅限于隱藏,而對于變量,static還有下面兩個作用。
?b:保持變量的持久
代碼1:
#include <stdio.h>void func() {static int x = 0; // 在對func的三次調用中,x只進行一次初始化printf("%d\n", x); // 輸出x的值x = x + 1; }int main(int argc, char * const argv[]) {func(); // 輸出0func(); // 輸出1func(); // 輸出2return 0; }?代碼2:
//C中static的封裝性。 //換句話說,封裝在函數內的static變量只在本函數內部可見。 #include <iostream> using namespace std; int fun(void) {//static int count = 10; //事實上此賦值語句從來沒有執行過/*此時輸出結果為:1 10;2 9;3 8;4 7......*/int count = 10; //事實上此賦值語句從來沒有執行過/*此時輸出結果為:1 10;2 10;3 10;4 10......*/return count--; }int count = 1; //全局變量void main() {cout<<"Output the data"<<endl;;for(; count <= 10; ++count)cout<<count<<' '<<fun()<<endl; }?????? 此例中,static int count = 10將count分配在靜態存儲區,可見區域范圍是fun()函數內部,而且其值在整個程序運行時均存在,并沒有因為fun函數作用域的消失而消失,而是整個函數均保留。
全局變量也是存儲在靜態存儲區,static和全局變量的區別在哪里?他們的可見區域不同,如上面的例子,若不用static那么改用全局變量也是可以,但是用全局變量,其他函數也可見,也可用,這會破壞函數的封裝性。
c:具有默認值0
???? 在靜態數據區,內存中所有的字節默認值都是0x00,某些時候這一特點可以減少程序員的工作量。比如初始化一個稀疏矩陣,我們可以一個一個地把所有元素都置0,然后把不是0的幾個元素賦值。如果定義成靜態的,就省去了一開始置0的操作。再比如要把一個字符數組當字符串來用,但又覺得每次在字符數組末尾加‘\0’太麻煩。如果把字符串定義成靜態的,就省去了這個麻煩,因為那里本來就是‘\0’。不妨做個小實驗驗證一下。?
代碼3:
?
#include <stdio.h>int a;int main(void){int i;static char str[10];printf("integer: %d; string: (begin)%s(end)", a, str);return 0;}?
?程序的運行結果如下integer: 0; string: (begin)(end)
最后對static的三條作用做一句話總結
?首先static的最主要功能是隱藏;
其次因為static變量存放在靜態存儲區,具有和全局變量相同的功能,所以它具備持久性和默認值0;
二.外部靜態變量和函數
?
??? 在C中 static有了第二種含義:用來表示不能被其它文件訪問的全局變量和函數。但為了限制全局變量/函數的作用域, 函數或變量前加static使得函數成為靜態函數。但此處“static”的含義不是指存儲方式,而是指對函數的作用域僅局限于本文件(所以又稱內部函 數)。注意此時, 對于外部(全局)變量, 不論是否有static限制, 它的存儲區域都是在靜態存儲區,生存期都是全局的. 此時的static只是起作用域限制作用, 限定作用域在本模塊(文件)內部.使用內部函數的好處是:不同的人編寫不同的函數時,不用擔心自己定義的函數,是否會與其它文件中的函數同名。
?
?
//C中static的隱藏性。 //file1.cppstatic int varA; int varB; extern void funA() {…… }static void funB() {…… }//file2.cppextern int varB; // 使用file1.cpp中定義的全局變量 extern int varA; // 錯誤! varA是static類型, 無法在其他文件中使用 extern vod funA(); // 使用file1.cpp中定義的函數 extern void funB(); // 錯誤! 無法使用file1.cpp文件中static函數?
-----------------------------------------------------------------------------------------------
?三. 靜態成員變量和函數(C++)
對此,我們可以從兩個方面考慮
a:靜態成員變量
????? 在類中,靜態成員可以實現多個對象之間的數據共享,并且使用靜態數據成員還不會破壞隱藏的原則,即保證了安全性。因此,靜態成員是類的所有對象中共享的成員,而不是某個對象的成員。
????? 使用靜態數據成員可以節省內存,因為它是所有對象所公有的,因此,對多個對象來說,靜態數據成員只存儲一處,供所有對象共用。靜態數據成員的值對每個對象都是一樣,但它的值是可以更新的。只要對靜態數據成員的值更新一次,保證所有對象存取更新后的相同的值,這樣可以提高時間效率。
??????? 靜態數據成員的使用方法和注意事項如下:
??????? 1、靜態數據成員在定義或說明時前面加關鍵字static。
2、靜態成員初始化與一般數據成員初始化不同。靜態數據成員初始化的格式如下:
<數據類型><類名>::<靜態數據成員名>=<值>
這表明:
????? (1) 初始化在類體外進行,而前面不加static,以免與一般靜態變量或對象相混淆。
????? (2) 初始化時不加該成員的訪問權限控制符private,public等。
????? (3) 初始化時使用作用域運算符來標明它所屬類,因此,靜態數據成員是類的成員,而不是對象的成員。
3、靜態數據成員是靜態存儲的,它是靜態生存期,必須對它進行初始化。
4、引用靜態數據成員時,采用如下格式:
<類名>::<靜態成員名>
??? 如果靜態數據成員的訪問權限允許的話(即public的成員),可在程序中,按上述格式來引用靜態數據成員。
?????????? 我們通過下面的例子來解釋C++中靜態數據成員變量的問題:
??????????
#include <iostream> using namespace std;class Myclass { public:Myclass(int a, int b, int c);void GetSum(); private:int A, B, C;static int Sum; //define a private static member };int Myclass::Sum = 0; //set value for the static member in the outclassMyclass::Myclass(int a, int b, int c) {A = a;B = b;C = c;Sum += A+B+C; }void Myclass::GetSum() {cout<<"Sum="<<Sum<<endl;}void main() {Myclass M(3, 7, 10),N(14, 9, 11);M.GetSum(); //輸出結果為54N.GetSum(); //輸出結果為54 }?
?從輸出結果可以看到Sum的值對M對象和對N對象都是相等的。這是因為在初始化M對象時,將M對象的三個int型數據成員的值求和后賦給了Sum,
于是Sum保存了該值。在初始化N對象時,對將N對象的三個int型數據成員的值求和后又加到Sum已有的值上,于是Sum將保存另后的值。所以,不論是通過對象M還是通過對象N來引用的值都是一樣的,即為54。
?
??????
b:靜態成員函數
?靜態成員函數和靜態數據成員一樣,它們都屬于類的靜態成員,它們都不是對象成員。因此,對靜態成員的引用不需要用對象名。
在靜態成員函數的實現中不能直接引用類中說明的非靜態成員,可以引用類中說明的靜態成員。
如果靜態成員函數中要引用非靜態成員時,可通過對象來引用。下面通過例子來說明這一點。
//調用靜態成員函數 #include <iostream> using namespace std;class M { public:M(int a) { A=a; B+=a;}static void f1(M m); private:int A;static int B; };void M::f1(M m) {cout<<"A="<<m.A<<endl;cout<<"B="<<B<<endl;}int M::B=0; void main() {M P(5);M Q(10);M::f1(P); //調用時不用對象名M::f1(Q); }?輸出結果為:
5
15
10
15
很容易理解:當執行M P(5)時,調用構造函數,將5賦值給A,并將5賦值給靜態變量B,然后執行M Q(10),由于B為靜態成員變量,
所以B的第一次執行的結果保持不變,最后輸出結果。
?
參考鏈接:http://www.cnblogs.com/Kane_zzt/archive/2009/05/18/1459697.html
???????????? http://www.yesky.com/20010828/194000.shtml
?
轉載于:https://www.cnblogs.com/CBDoctor/archive/2012/06/25/2561426.html
總結
以上是生活随笔為你收集整理的全局变量、静态全局变量、静态局部变量和局部变量的区别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL语句获取数据库名、所有表名、所有字
- 下一篇: strong与em、q、cite、blo