1. 程式人生 > >C++學習之:變數的儲存類別

C++學習之:變數的儲存類別

在c++中,每個變數有兩個屬性:

  1. 型別:變數所儲存的資料型別(如int、double、char);
  2. 儲存型別:變數所儲存的區域(atuo、register、extern、static)

變數的作用域決定了變數的有效範圍。變數的儲存類別決定了變數的生存期限。在計算機中,記憶體被分成不同的區域。不同區域與不同的用途。按變數在計算機內的儲存位置來分,變數分為:自動變數(atuo)、靜態變數(static)、暫存器變數(register)、和外部變數(extern)。變數的儲存位置稱為變數的儲存類別。c++中完整的變數定義格式為:

儲存類別 資料型別 變數名;

1.暫存器變數(register)

儲存在暫存器中,代替自動變數或形參,可以提高變數的訪問速度。

register int x;//表示x不是儲存在記憶體中,而是儲存在暫存器中
2.外部變數(extern)

外部變數一定是全域性變數。全域性變數的作用域是從變數定義處到檔案結束。如果在定義點以前的函式或另一原始檔中的函式也要使用該全域性變數,則在引用之前,應該對此全域性變數用關鍵字extern進行外部變數宣告,否則編譯器會認為使用了一個沒有定義過的變數。

//file1.cpp
#include <iostream>
using namespace std;

void f();
extern int x; //外部變數的宣告

int main()
{  
   f();
   cout << "in main(): x= “
           << x << endl;
   return 0;
}

//file2.cpp
#include <iostream>
using namespace std;

int x; //全域性變數的定義

void f()
 { 
    cout << "in f(): x= “
             << x << endl;
} 
#include <iostream>
using namespace std;
void f();

int main()
{
    extern int x;
    f();
    cout << "in main(): x= " << x << endl;
    return 0;
}

int x;

void f()
{
    cout << "in f(): x= " << x << endl;
} 

用途:

  1. 在某一函式中應用了一個宣告在本函式後的全域性變數時,需要在函式內用extern宣告此全域性變數。
  2. 當一個程式有多個原始檔組成時,用extern可引用另一個檔案中的全域性變數。

3.自動變數(atuo)

函式中的區域性變數、形參或程式塊中定義的變數,如不專門宣告為其他儲存型別,都是自動變數。不指名儲存型別的定義都是指自動變數型別的儲存型別。如下面兩個定義是等價的:

auto int a,b;
//等價於:
int a,b;

自動變數儲存在記憶體中的區域中。

4.靜態變數

如果程式執行過程中某些變數自始至終都必須存在,如全域性變數,那麼這些變數被儲存在記憶體的全域性變數區,如果想限制這些變數只在某一個範圍內才能使用,用static來限定。儲存類別指定為static的變數稱為靜態變數。區域性變數和全域性變數都可以定義為靜態的。

     4.1靜態的全域性變數

    如果在一個原始檔的頭上定義了一個全域性變數,則該原始檔中的所有函式都能使用該全域性變數。事實上該程式中的其他原始檔中的函式也能使用該全域性變數。但在一個結構良好的程式中,一般是不希望多個原始檔共享某一個全域性變數。要做到這一點可以使用靜態的全域性變數。比如在定義全域性變數前加上關鍵字static。如:

static int x;//表示該全域性變數是當前原始檔私有的,只有本原始檔中的函式才可以引用它,其他原始檔中的函式是不能引用它的
  • 用static說明的全域性變數,其他原始檔不能用extern引用它,因為它只供本原始檔使用。
  • 用extern還可以用在函式定義或說明中,該函式只能被用於本原始檔中,其他原始檔不能呼叫此函式
//file1.cpp
#include <iostream>
using namespace std;

void f();
extern int x;     //出錯,因為static int x 只能在file2.cpp中使用

int main()
{  
   f();
   cout << "in main(): x= “
           << x << endl;
   return 0;
}

//file2.cpp
#include <iostream>
using namespace std;

static  int  x; 

void f()
 { 
    cout << "in f(): x= “
             << x << endl;
} 

    4.2 靜態的區域性變數

如果把一個區域性變數定義為static,該變數就不再存放在函式對應的幀中,而是存放在全域性變數區。當函式執行結束後,該變數不會消失,在下一次呼叫該函式時,也不會再建立該變數,而是繼續使用原空間中的值。這樣就可以把上一次函式呼叫的某些資訊帶到下一次函式呼叫中。

  • 第一次呼叫函式時定義
  • 函式執行結束時消亡
  • 再次呼叫函式時不再重新定義,繼續沿用原有空間
int f(int a)
     {   int b=0;
          static int c=3;
          b=b+1; 
          c=c+1;
          return(a+b+c);
      }
      int main()
      {  int a=2,i;
          for (i=0; i<3; ++i)
             cout << f(a);//運算結果為7、8、9
          return 0;
      }

總結:靜態變數使用時必須注意四點:

  • 未被程式設計師初始化的靜態變數都由系統初始化為0。
  • 區域性靜態變數的初值是編譯賦的,當執行時重複呼叫該函式時,由於沒有重新分配空間,因此也不做初始化。
  • 雖然區域性靜態變數在函式呼叫結束後仍然存在,但其他函式不能引用它
  • 區域性的靜態變數在程式執行結束後消亡。如果程式中既有靜態的區域性變數又有全域性變數,系統先消亡靜態的區域性變數,再消亡全域性變數。

補充:全域性變數與區域性變數

全域性變數和區域性變數的作用範圍:從定義位置後的函式都能使用此變數

1.區域性變數

    在塊內定義的變數稱為區域性變數,即使是main函式中定義的變數也是區域性變數。當外部塊與內部塊有共同識別符號時,在內部塊中遮蔽外部塊的同名識別符號。

2.全域性變數

在所有函式外邊(包括main函式)定義的變數稱為全域性變數。全域性變數被儲存在一個在整個程式執行期間始終有效的獨立記憶體區域,永遠都不會被包含區域性變數的幀覆蓋。程式中每個函式都可以看到,並操作這塊獨立區域上的這些變數。全域性變數的作用域是原始檔中定義它的位置後的其餘部分。

全域性變數增加了函式間的聯絡渠道。由於同一原始檔中的所有函式都能引用全域性變數,因此,當一個函式改變了某個全域性變數的值,其他的函式都能看見。

在區域性變數與全域性變數

比如下面的示例程式

int  p = 1,  q = 5, r=3; //全域性變數
int f1()
{ int p = 3,  r = 2;
  q=p+q+r;  cout << “f1: p,q,r=“ << p << q << r; //函式f1操作了全域性變數q
}
int f2()
{
  p=p+q+r;  cout << “f2: p,q,r=“ << p << q << r;
}
int f3()
{ int q;    r = 2*r;  q=r+p;
  cout << “f3: p,q,r=“ << p << q << r;
}
int main()
{ f3(); cout << “after f3: p,q,r=” << p << q < r;
  f1(); cout << “after f1: p,q,r=“  << p << q << r;
  f2(); cout << “after f2: p,q,r=” << p << q << r;
  return 0;
 } 
運算結果:
f3:p,q,r=1 7 6
after f3: p,q,r=1 5 6 
f1: p,q,r=3 10 2 
after f1:p,q,r=1 10 6 
f2: p,q,r=17 10 6 
after f2: p,q,r=17 10 6