C++中static初始化一次的真實含義

海_纳百川發表於2024-11-30

1. static 變數的初始化與賦值

static 變數在 C++ 中有一個特別的性質:它們在程式的生命週期內只會被初始化一次,但之後可以繼續對其進行賦值。

  • 初始化static 變數在程式的初始化階段(即程式第一次執行時)會被初始化一次。如果是區域性 static 變數,則它會在第一次執行到該變數所在的程式碼行時被初始化;如果是全域性或靜態作用域內的變數,則會在程式啟動時初始化。

  • 賦值:初始化之後,static 變數的值是可以改變的。賦值操作不會改變 static 變數的記憶體地址,也就是說,static 變數的記憶體地址在整個程式執行期間是固定的。賦值只會改變該記憶體地址中儲存的資料,而不會影響變數的地址。

示例:static 變數的初始化和賦值

#include <iostream>

void testStatic() {
    static int x = 10;  // 初始化只發生一次
    std::cout << "x = " << x << std::endl;
    x = 20;  // 賦值,但不重新初始化
    std::cout << "x after assignment = " << x << std::endl;
}

int main() {
    testStatic();  // 第一次呼叫,初始化並賦值為 10
    testStatic();  // 第二次呼叫,x 已初始化,賦值為 20
    return 0;
}

輸出:

x = 10
x after assignment = 20
x = 20
x after assignment = 20

在這個例子中,xstatic 變數:

  • 第一次呼叫 testStatic() 時,x 會被初始化為 10,之後賦值為 20。
  • 第二次呼叫 testStatic() 時,x 不會重新初始化,而是保持上次賦的值(20),並可以繼續賦值。

記憶體地址不變:無論你如何對 x 進行賦值,x 的記憶體地址始終不變,它依然指向同一塊記憶體位置。

2. 普通變數的初始化與賦值

對於普通的區域性變數,每次進入其作用域時,該變數會被重新初始化,並且會在棧上分配新的記憶體空間。普通變數 可以多次初始化,但每次進入作用域時,都會重新為該變數分配記憶體(除非它是動態分配的,如使用 new)。

  • 初始化:每次進入作用域時,區域性變數都會被重新初始化,並且會重新分配棧空間。
  • 賦值:可以在初始化之後對普通變數進行賦值,但賦值不等於初始化。賦值操作會改變該變數儲存的值,而不會影響它的記憶體位置(除非你是指標型別)。

示例:普通區域性變數的初始化和賦值

#include <iostream>

void testNormal() {
    int x = 10;  // 每次進入函式時都會初始化
    std::cout << "x = " << x << std::endl;
    x = 20;  // 賦值,但記憶體地址不變
    std::cout << "x after assignment = " << x << std::endl;
}

int main() {
    testNormal();  // 第一次呼叫,初始化為 10
    testNormal();  // 第二次呼叫,重新初始化為 10
    return 0;
}

輸出:

x = 10
x after assignment = 20
x = 10
x after assignment = 20

在這個例子中,x 是普通的區域性變數:

  • 每次呼叫 testNormal()x 會被重新初始化,並且會重新分配棧空間。
  • x 的值在初始化後可以被賦值為其他值,但它的記憶體地址在每次呼叫 testNormal() 時都是新的,棧空間會被重新分配。

3. 對比:static 變數與普通變數的差異

特性static 變數普通區域性變數
初始化 只初始化一次,在程式啟動或首次呼叫時初始化 每次進入作用域時初始化
賦值 之後可以多次賦值,但不改變記憶體地址 可以多次賦值,但記憶體地址隨每次進入作用域不同
記憶體管理 只有一塊記憶體空間,記憶體地址固定 每次進入作用域時會重新分配記憶體
生命週期 整個程式執行期間(從程式啟動到結束) 僅在作用域內有效,出作用域時銷燬

4. 棧空間與堆空間的對比(記憶體分配)

  • 棧空間(stack):區域性變數(普通變數)通常儲存在棧上。每次進入作用域時,棧空間會為變數分配記憶體,離開作用域時銷燬。這是 自動記憶體管理

  • 堆空間(heap):使用 newmalloc 分配的記憶體則來自堆。堆上的記憶體通常需要顯式釋放(如透過 deletefree),否則會導致記憶體洩漏。

5. 結論

  • static 變數:初始化只發生一次,記憶體地址在整個程式的生命週期內固定,不會發生變化。之後的賦值只是改變其儲存的值,而不會改變記憶體地址。
  • 普通區域性變數:每次進入作用域時會重新分配記憶體,並且會重新初始化。因此,每次函式呼叫時,區域性變數的記憶體空間是不同的。

總結來說,static 變數不會在每次呼叫時重新分配記憶體,它的記憶體地址是固定的,而普通區域性變數每次進入作用域時都會重新分配記憶體,記憶體地址不同。

相關文章