自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一字千金:C語(yǔ)言中的 static:一個(gè)關(guān)鍵字,三種超能力 !

開(kāi)發(fā)
今天咱們來(lái)聊一個(gè)看起來(lái)普普通通,用起來(lái)卻異常強(qiáng)大的 C 語(yǔ)言關(guān)鍵字——static。它就像是代碼中的"隱形斗篷",神不知鬼不覺(jué)地改變著你程序的行為。

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

今天咱們來(lái)聊一個(gè)看起來(lái)普普通通,用起來(lái)卻異常強(qiáng)大的 C 語(yǔ)言關(guān)鍵字——static。它就像是代碼中的"隱形斗篷",神不知鬼不覺(jué)地改變著你程序的行為。

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

一、static 是啥玩意兒?不就是個(gè)關(guān)鍵字嗎?

別小看這個(gè)小小的關(guān)鍵字,它可是 C 語(yǔ)言中的多面手!根據(jù)不同的使用場(chǎng)景,static 有著完全不同的功能:

  • 用在 局部變量 前面:讓變量擁有"記憶力"
  • 用在 全局變量/函數(shù) 前面:讓它們變得"害羞"(只在本文件可見(jiàn))
  • 用在 類(lèi)/結(jié)構(gòu)體成員 前面:讓所有對(duì)象共享一個(gè)變量

好家伙,一個(gè)詞能干三種活,難怪很多人搞不明白!但別擔(dān)心,我們一個(gè)一個(gè)來(lái)解釋?zhuān)WC你能徹底搞懂!

二、場(chǎng)景一:給局部變量加上"記憶力"

平常我們定義的局部變量,函數(shù)調(diào)用結(jié)束后就"揮手告別"了,下次再調(diào)用函數(shù)時(shí),變量又會(huì)重新初始化。但加上 static 后,這個(gè)變量就有了"記憶力",能夠記住上次函數(shù)調(diào)用后的值!

看個(gè)例子就明白了:

#include <stdio.h>

// 沒(méi)有static的普通函數(shù)
void normalCounter() {
    int count = 0;  // 每次調(diào)用都會(huì)重置為0
    count++;
    printf("普通計(jì)數(shù)器:%d\n", count);
}

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

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

運(yùn)行結(jié)果:

普通計(jì)數(shù)器:1
static計(jì)數(shù)器:1
-------------------
普通計(jì)數(shù)器:1
static計(jì)數(shù)器:2
-------------------
普通計(jì)數(shù)器:1
static計(jì)數(shù)器:3
-------------------

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

這有啥用?想想以下場(chǎng)景:

  • 需要記錄函數(shù)被調(diào)用了多少次
  • 需要緩存計(jì)算結(jié)果,避免重復(fù)計(jì)算
  • 需要檢測(cè)是否是第一次調(diào)用函數(shù)

static 局部變量的特點(diǎn):

  • 值會(huì)保留:函數(shù)調(diào)用結(jié)束后,變量的值不會(huì)消失
  • 只初始化一次:static int x = 10; 這個(gè)初始化只會(huì)在程序第一次執(zhí)行到這句話時(shí)進(jìn)行
  • 內(nèi)存位置:放在靜態(tài)存儲(chǔ)區(qū),而不是棧上
  • 默認(rèn)值為0:如果不初始化,自動(dòng)設(shè)為 0(普通局部變量不初始化則是隨機(jī)值)

三、場(chǎng)景二:讓全局變量/函數(shù)變"害羞"(限制可見(jiàn)性)

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

這時(shí)候,static 就派上用場(chǎng)了!它能讓全局變量和函數(shù)變得"害羞"起來(lái),只在定義它的文件內(nèi)可見(jiàn)。

假設(shè)我們有兩個(gè)文件:

  • file1.c
#include <stdio.h>

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

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

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

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

// 公開(kāi)函數(shù),內(nèi)部使用私有計(jì)數(shù)器
void accessPrivate() {
    increasePrivate();  // 可以調(diào)用static函數(shù)
    printf("通過(guò)接口訪問(wèn)私有計(jì)數(shù)器\n");
}
  • file2.c
#include <stdio.h>

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

// 無(wú)法訪問(wèn)privateCounter,因?yàn)樗莝tatic的

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

int main() {
    increaseGlobal();  // 可以調(diào)用
    // increasePrivate();  // 錯(cuò)誤!無(wú)法調(diào)用static函數(shù)
    accessPrivate();   // 可以通過(guò)公開(kāi)接口間接使用
    
    printf("在main中訪問(wèn)全局計(jì)數(shù)器:%d\n", globalCounter);
    // printf("在main中訪問(wèn)私有計(jì)數(shù)器:%d\n", privateCounter);  // 錯(cuò)誤!無(wú)法訪問(wèn)
    
    return0;
}

輸出結(jié)果:

全局計(jì)數(shù)器:1
私有計(jì)數(shù)器:1
通過(guò)接口訪問(wèn)私有計(jì)數(shù)器
在main中訪問(wèn)全局計(jì)數(shù)器:1

這個(gè)例子說(shuō)明:

  • globalCounter和increaseGlobal()在兩個(gè)文件間共享
  • privateCounter和increasePrivate()只在 file1.c 中可見(jiàn)
  • 需要使用私有功能時(shí),必須通過(guò)公開(kāi)的"接口函數(shù)"如accessPrivate()

static 全局變量/函數(shù)的特點(diǎn):

  • 限制作用域:只在定義的文件內(nèi)可見(jiàn)
  • 避免命名沖突:不同文件可以使用相同名稱(chēng)的 static 變量/函數(shù)
  • 隱藏實(shí)現(xiàn)細(xì)節(jié):將內(nèi)部使用的輔助函數(shù)設(shè)為 static
  • 提高編譯效率:編譯器可以對(duì) static 函數(shù)進(jìn)行更多優(yōu)化

四、場(chǎng)景三:在結(jié)構(gòu)體/類(lèi)中創(chuàng)建共享變量

C++中,可以在類(lèi)中定義 static 成員變量,所有對(duì)象共享同一個(gè)變量。雖然 C 語(yǔ)言沒(méi)有類(lèi),但在一些 C++風(fēng)格的C 代碼中也會(huì)用到這個(gè)概念:

#include <stdio.h>

// 假設(shè)這是一個(gè)簡(jiǎn)單的"類(lèi)"
typedefstruct {
    int id;
    char* name;
    // 注意:在C中不能在結(jié)構(gòu)體內(nèi)直接定義static變量
} Person;

// 在C中,我們?cè)诮Y(jié)構(gòu)體外定義static變量
staticint Person_count = 0;

// "構(gòu)造函數(shù)"
Person createPerson(char* name) {
    Person p;
    p.id = ++Person_count;  // 每創(chuàng)建一個(gè)Person,計(jì)數(shù)器就+1
    p.name = name;
    return p;
}

// 獲取創(chuàng)建的Person總數(shù)
int getPersonCount() {
    return Person_count;
}

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

運(yùn)行結(jié)果:

已創(chuàng)建的Person對(duì)象數(shù)量:3
各Person的ID:1, 2, 3

在這個(gè)例子中,Person_count在所有Person對(duì)象之間共享,用來(lái)記錄創(chuàng)建了多少個(gè)對(duì)象,并為每個(gè)對(duì)象分配唯一ID。

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

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

生命周期:變量存在的時(shí)間

  • 普通局部變量:函數(shù)調(diào)用期間存在
  • static 局部變量:程序運(yùn)行期間一直存在

作用域:變量可見(jiàn)的范圍

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

六、幾個(gè)常見(jiàn)的 static 使用場(chǎng)景

1. 單例模式的實(shí)現(xiàn)(非線程安全)

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

typedefstruct {
    int data;
} Singleton;

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

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

運(yùn)行結(jié)果:

創(chuàng)建了單例對(duì)象
s1的地址:00C37F28, 數(shù)據(jù):42
s2的地址:00C37F28, 數(shù)據(jù):42
修改后,s2的數(shù)據(jù):100

這個(gè)例子實(shí)現(xiàn)了單例模式:無(wú)論調(diào)用多少次getInstance(),都只會(huì)創(chuàng)建一個(gè)Singleton對(duì)象。

不過(guò)要注意,這個(gè)實(shí)現(xiàn)在多線程環(huán)境下可能會(huì)出問(wèn)題。想象兩個(gè)線程同時(shí)首次調(diào)用 getInstance(),它們都發(fā)現(xiàn)instance == NULL,然后都創(chuàng)建了對(duì)象!解決這個(gè)問(wèn)題需要加鎖或使用原子操作,這就是所謂的"線程安全單例模式"。

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

#include <stdio.h>

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

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

這個(gè)例子使用 static 數(shù)組緩存了已計(jì)算的結(jié)果,大大提高了效率。

七、static 的常見(jiàn)坑和注意事項(xiàng)

  • 不要在頭文件中定義 static 全局變量/函數(shù) :  如果在頭文件中定義static變量/函數(shù),每個(gè)包含該頭文件的源文件都會(huì)創(chuàng)建自己的副本,可能導(dǎo)致意想不到的結(jié)果。
  • 初始化順序:  static 變量的初始化發(fā)生在程序啟動(dòng)時(shí),但是不同文件中的static變量初始化順序是不確定的。
  • 多線程安全問(wèn)題:  多線程同時(shí)訪問(wèn) static 變量可能導(dǎo)致競(jìng)態(tài)條件,需要使用互斥鎖保護(hù)。

八、總結(jié):static 的三個(gè)"超能力"

  • 記憶力:static 局部變量記住調(diào)用間的狀態(tài)
  • 隱身術(shù):static 全局變量/函數(shù)隱藏實(shí)現(xiàn)細(xì)節(jié)
  • 共享精神:static 在"類(lèi)"中用于共享數(shù)據(jù)

掌握了這三點(diǎn),你就能在編程中靈活運(yùn)用 static,讓你的程序更高效、更安全、更優(yōu)雅!

責(zé)任編輯:趙寧寧 來(lái)源: 跟著小康學(xué)編程
相關(guān)推薦

2015-11-10 16:10:22

C語(yǔ)言StaticConst

2024-06-04 17:02:38

newC#編程語(yǔ)言

2015-03-13 11:23:21

編程編程超能力編程能力

2024-05-29 14:09:00

C#編程this

2009-06-29 12:58:47

This關(guān)鍵字java

2011-07-14 23:14:42

C++static

2022-02-17 08:31:38

C語(yǔ)言staic關(guān)鍵字

2021-02-01 13:10:07

Staticc語(yǔ)言UNIX系統(tǒng)

2019-02-28 22:10:30

AI人工智能預(yù)測(cè)

2010-02-02 14:27:54

C++ static關(guān)

2024-12-31 00:05:24

new?關(guān)鍵字C#

2022-01-10 18:11:42

C語(yǔ)言應(yīng)用技巧

2024-03-15 08:18:25

volatileAtomic關(guān)鍵字

2011-04-21 16:57:56

staticextern

2024-04-08 11:35:34

C++static關(guān)鍵字

2011-02-22 17:48:34

Konqueror

2020-12-09 05:19:35

static關(guān)鍵字Java

2023-11-12 23:01:44

PaddleOCR深度學(xué)習(xí)

2009-09-02 09:24:03

C# this關(guān)鍵字

2009-08-21 14:58:56

C# this關(guān)鍵字
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)