成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一字千金:C語言中的 static:一個關鍵字,三種超能力 !

開發
今天咱們來聊一個看起來普普通通,用起來卻異常強大的 C 語言關鍵字——static。它就像是代碼中的"隱形斗篷",神不知鬼不覺地改變著你程序的行為。

嘿,各位編程小伙伴們!我是小康。

今天咱們來聊一個看起來普普通通,用起來卻異常強大的 C 語言關鍵字——static。它就像是代碼中的"隱形斗篷",神不知鬼不覺地改變著你程序的行為。

很多初學者對它一知半解,要么不敢用,要么用錯了還不知道為啥。今天我就用大白話幫你徹底搞懂它!

一、static 是啥玩意兒?不就是個關鍵字嗎?

別小看這個小小的關鍵字,它可是 C 語言中的多面手!根據不同的使用場景,static 有著完全不同的功能:

  • 用在 局部變量 前面:讓變量擁有"記憶力"
  • 用在 全局變量/函數 前面:讓它們變得"害羞"(只在本文件可見)
  • 用在 類/結構體成員 前面:讓所有對象共享一個變量

好家伙,一個詞能干三種活,難怪很多人搞不明白!但別擔心,我們一個一個來解釋,保證你能徹底搞懂!

二、場景一:給局部變量加上"記憶力"

平常我們定義的局部變量,函數調用結束后就"揮手告別"了,下次再調用函數時,變量又會重新初始化。但加上 static 后,這個變量就有了"記憶力",能夠記住上次函數調用后的值!

看個例子就明白了:

#include <stdio.h>

// 沒有static的普通函數
void normalCounter() {
    int count = 0;  // 每次調用都會重置為0
    count++;
    printf("普通計數器:%d\n", count);
}

// 使用static的函數
void staticCounter() {
    staticint count = 0;  // 只在第一次調用時初始化為0
    count++;              // 以后每次調用都在上次的基礎上+1
    printf("static計數器:%d\n", count);
}

int main() {
    // 調用3次看看效果
    for (int i = 0; i < 3; i++) {
        normalCounter();
        staticCounter();
        printf("-------------------\n");
    }
    return0;
}

運行結果:

普通計數器:1
static計數器:1
-------------------
普通計數器:1
static計數器:2
-------------------
普通計數器:1
static計數器:3
-------------------

看到差別了嗎?沒加 static 的count,每次都是從 0 開始,加 1 后變成 1;而加了 static 的count,第一次是1,第二次是 2,第三次是 3,它記住了自己上次的值!

這有啥用?想想以下場景:

  • 需要記錄函數被調用了多少次
  • 需要緩存計算結果,避免重復計算
  • 需要檢測是否是第一次調用函數

static 局部變量的特點:

  • 值會保留:函數調用結束后,變量的值不會消失
  • 只初始化一次:static int x = 10; 這個初始化只會在程序第一次執行到這句話時進行
  • 內存位置:放在靜態存儲區,而不是棧上
  • 默認值為0:如果不初始化,自動設為 0(普通局部變量不初始化則是隨機值)

三、場景二:讓全局變量/函數變"害羞"(限制可見性)

在沒有 static 的情況下,一個 C 文件(也叫翻譯單元)中定義的全局變量和函數,默認對其他文件也是可見的。但有時候,我們希望某些函數和變量是"內部實現細節",不想讓其他文件看到和使用。

這時候,static 就派上用場了!它能讓全局變量和函數變得"害羞"起來,只在定義它的文件內可見。

假設我們有兩個文件:

  • file1.c
#include <stdio.h>

// 普通全局變量:其他文件可以訪問
int globalCounter = 0;

// static全局變量:只有本文件能訪問
staticint privateCounter = 0;

// 普通函數:其他文件可以調用
void increaseGlobal() {
    globalCounter++;
    printf("全局計數器:%d\n", globalCounter);
}

// static函數:只有本文件能調用
static void increasePrivate() {
    privateCounter++;
    printf("私有計數器:%d\n", privateCounter);
}

// 公開函數,內部使用私有計數器
void accessPrivate() {
    increasePrivate();  // 可以調用static函數
    printf("通過接口訪問私有計數器\n");
}
  • file2.c
#include <stdio.h>

// 聲明外部全局變量
externint globalCounter;

// 無法訪問privateCounter,因為它是static的

// 聲明外部函數
void increaseGlobal();
void accessPrivate();

int main() {
    increaseGlobal();  // 可以調用
    // increasePrivate();  // 錯誤!無法調用static函數
    accessPrivate();   // 可以通過公開接口間接使用
    
    printf("在main中訪問全局計數器:%d\n", globalCounter);
    // printf("在main中訪問私有計數器:%d\n", privateCounter);  // 錯誤!無法訪問
    
    return0;
}

輸出結果:

全局計數器:1
私有計數器:1
通過接口訪問私有計數器
在main中訪問全局計數器:1

這個例子說明:

  • globalCounter和increaseGlobal()在兩個文件間共享
  • privateCounter和increasePrivate()只在 file1.c 中可見
  • 需要使用私有功能時,必須通過公開的"接口函數"如accessPrivate()

static 全局變量/函數的特點:

  • 限制作用域:只在定義的文件內可見
  • 避免命名沖突:不同文件可以使用相同名稱的 static 變量/函數
  • 隱藏實現細節:將內部使用的輔助函數設為 static
  • 提高編譯效率:編譯器可以對 static 函數進行更多優化

四、場景三:在結構體/類中創建共享變量

C++中,可以在類中定義 static 成員變量,所有對象共享同一個變量。雖然 C 語言沒有類,但在一些 C++風格的C 代碼中也會用到這個概念:

#include <stdio.h>

// 假設這是一個簡單的"類"
typedefstruct {
    int id;
    char* name;
    // 注意:在C中不能在結構體內直接定義static變量
} Person;

// 在C中,我們在結構體外定義static變量
staticint Person_count = 0;

// "構造函數"
Person createPerson(char* name) {
    Person p;
    p.id = ++Person_count;  // 每創建一個Person,計數器就+1
    p.name = name;
    return p;
}

// 獲取創建的Person總數
int getPersonCount() {
    return Person_count;
}

int main() {
    Person p1 = createPerson("張三");
    Person p2 = createPerson("李四");
    Person p3 = createPerson("王五");
    
    printf("已創建的Person對象數量:%d\n", getPersonCount());
    printf("各Person的ID:%d, %d, %d\n", p1.id, p2.id, p3.id);
    
    return0;
}

運行結果:

已創建的Person對象數量:3
各Person的ID:1, 2, 3

在這個例子中,Person_count在所有Person對象之間共享,用來記錄創建了多少個對象,并為每個對象分配唯一ID。

五、深入理解 static:生命周期 vs 作用域

很多人搞混了 static 的兩個作用:改變 生命周期和改變 作用域。

生命周期:變量存在的時間

  • 普通局部變量:函數調用期間存在
  • static 局部變量:程序運行期間一直存在

作用域:變量可見的范圍

  • 普通全局變量:所有文件可見
  • static 全局變量:僅定義它的文件可見

六、幾個常見的 static 使用場景

1. 單例模式的實現(非線程安全)

#include <stdio.h>
#include <stdlib.h>

typedefstruct {
    int data;
} Singleton;

Singleton* getInstance() {
    static Singleton* instance = NULL;
    
    if (instance == NULL) {
        // 第一次調用時創建對象
        instance = (Singleton*)malloc(sizeof(Singleton));
        instance->data = 42;
        printf("創建了單例對象\n");
    }
    
    return instance;
}

int main() {
    Singleton* s1 = getInstance();
    Singleton* s2 = getInstance();
    
    printf("s1的地址:%p, 數據:%d\n", (void*)s1, s1->data);
    printf("s2的地址:%p, 數據:%d\n", (void*)s2, s2->data);
    
    // 修改s1的數據
    s1->data = 100;
    
    // 檢查s2是否也改變了
    printf("修改后,s2的數據:%d\n", s2->data);
    
    // 注意:在實際應用中還需要處理內存釋放問題
    
    return0;
}

運行結果:

創建了單例對象
s1的地址:00C37F28, 數據:42
s2的地址:00C37F28, 數據:42
修改后,s2的數據:100

這個例子實現了單例模式:無論調用多少次getInstance(),都只會創建一個Singleton對象。

不過要注意,這個實現在多線程環境下可能會出問題。想象兩個線程同時首次調用 getInstance(),它們都發現instance == NULL,然后都創建了對象!解決這個問題需要加鎖或使用原子操作,這就是所謂的"線程安全單例模式"。

2. 計算斐波那契數列(使用緩存)

#include <stdio.h>

// 使用static數組緩存結果,避免重復計算
unsigned long long fibonacci(int n) {
    staticunsignedlonglong cache[100] = {0};  // 緩存結果
    staticint initialized = 0;
    
    // 初始化前兩個數
    if (!initialized) {
        cache[0] = 0;
        cache[1] = 1;
        initialized = 1;
    }
    
    // 如果結果已經計算過,直接返回
    if (cache[n] != 0 || n <= 1) {
        return cache[n];
    }
    
    // 計算并緩存結果
    cache[n] = fibonacci(n-1) + fibonacci(n-2);
    return cache[n];
}

int main() {
    printf("斐波那契數列的第40個數:%llu\n", fibonacci(39));
    // 再次計算,會直接使用緩存
    printf("再次計算,斐波那契數列的第40個數:%llu\n", fibonacci(39));
    
    return0;
}

這個例子使用 static 數組緩存了已計算的結果,大大提高了效率。

七、static 的常見坑和注意事項

  • 不要在頭文件中定義 static 全局變量/函數 :  如果在頭文件中定義static變量/函數,每個包含該頭文件的源文件都會創建自己的副本,可能導致意想不到的結果。
  • 初始化順序:  static 變量的初始化發生在程序啟動時,但是不同文件中的static變量初始化順序是不確定的。
  • 多線程安全問題:  多線程同時訪問 static 變量可能導致競態條件,需要使用互斥鎖保護。

八、總結:static 的三個"超能力"

  • 記憶力:static 局部變量記住調用間的狀態
  • 隱身術:static 全局變量/函數隱藏實現細節
  • 共享精神:static 在"類"中用于共享數據

掌握了這三點,你就能在編程中靈活運用 static,讓你的程序更高效、更安全、更優雅!

責任編輯:趙寧寧 來源: 跟著小康學編程
相關推薦

2015-11-10 16:10:22

C語言StaticConst

2024-06-04 17:02:38

newC#編程語言

2015-03-13 11:23:21

編程編程超能力編程能力

2024-05-29 14:09:00

C#編程this

2019-02-28 22:10:30

AI人工智能預測

2009-06-29 12:58:47

This關鍵字java

2011-07-14 23:14:42

C++static

2024-12-31 00:05:24

new?關鍵字C#

2022-02-17 08:31:38

C語言staic關鍵字

2021-02-01 13:10:07

Staticc語言UNIX系統

2022-01-10 18:11:42

C語言應用技巧

2024-03-15 08:18:25

volatileAtomic關鍵字

2010-02-02 14:27:54

C++ static關

2011-02-22 17:48:34

Konqueror

2023-11-12 23:01:44

PaddleOCR深度學習

2024-04-08 11:35:34

C++static關鍵字

2011-04-21 16:57:56

staticextern

2021-08-03 21:24:13

ARVR

2020-12-09 05:19:35

static關鍵字Java

2019-03-28 09:26:26

數據科學模型機器學習
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 天天综合网天天综合色 | 拍戏被cao翻了h承欢 | 欧美日韩一区二区三区四区 | 午夜免费成人 | 日本精品久久 | 国产二区在线播放 | 天堂综合网久久 | 日韩欧美高清 | 亚洲精品在线视频 | 91亚洲国产成人久久精品网站 | 一区二区在线不卡 | a在线视频观看 | 日韩国产在线 | 狠狠操狠狠操 | 妹子干综合 | 亚洲理论在线观看电影 | www.com久久久 | 国产乱码精品1区2区3区 | 精品国产乱码久久久久久老虎 | 不卡一区 | 亚洲国产精品第一区二区 | 国产成人啪免费观看软件 | 国产精品久久久久久久午夜 | 中文字幕精品视频 | 亚洲精品永久免费 | 亚洲美女在线一区 | 91久色| 综合网在线 | 青青久视频 | 婷婷综合网| 美日韩一区二区 | 国产亚洲精品美女久久久久久久久久 | 亚洲激情第一页 | www日本在线 | 日韩在线观看网站 | www.色.com| 国产一区不卡在线观看 | 91视频大全 | 99久久电影 | 天天干天天草 | 亚洲第一中文字幕 |