日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

动态内存分配及变量存储类别(第二部分)

發(fā)布時(shí)間:2023/12/13 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 动态内存分配及变量存储类别(第二部分) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

5. C語言變量的存儲(chǔ)類別和生存期

我們知道,變量是有數(shù)據(jù)類型的,用以說明它占用多大的內(nèi)存空間,可以進(jìn)行什么樣的操作。

除了數(shù)據(jù)類型,變量還有一個(gè)屬性,稱為“存儲(chǔ)類別”存儲(chǔ)類別就是數(shù)據(jù)在內(nèi)存中的存放區(qū)域。一個(gè)正在運(yùn)行的C程序的內(nèi)存空間可以分為五個(gè)區(qū)域:程序代碼區(qū)、靜態(tài)數(shù)據(jù)區(qū)、堆區(qū)、棧區(qū)和命令行參數(shù)區(qū),其中靜態(tài)數(shù)據(jù)區(qū)和棧區(qū)可以用來存放變量的值。

靜態(tài)數(shù)據(jù)區(qū)的內(nèi)存在程序啟動(dòng)時(shí)就已經(jīng)由操作系統(tǒng)分配好,占用的空間固定,程序運(yùn)行期間不再改變,程序運(yùn)行結(jié)束后才由操作系統(tǒng)釋放;它可以存放全局變量、靜態(tài)變量、一般常量和字符串常量。

棧區(qū)的內(nèi)存在程序運(yùn)行期間由操作系統(tǒng)根據(jù)需要來分配使用到變量才分配內(nèi)存;如果定義了變量但沒有執(zhí)行到該代碼,也不會(huì)分配內(nèi)存),占用的空間實(shí)時(shí)改變,使用完畢后立即釋放,不必等到程序運(yùn)行結(jié)束;它可以存放局部變量、函數(shù)參數(shù)等。

可以通過C語言中的關(guān)鍵字來控制變量的存放區(qū)域;C語言共有 4 個(gè)關(guān)鍵字用來指明變量的存儲(chǔ)類別:auto(自動(dòng)的)、static(靜態(tài)的)、register(寄存器的)、extern(外部的)。

知道了變量的存儲(chǔ)類別,就可以知道變量的生存期。通俗地講,生存期指的是在程序運(yùn)行過程中,變量從創(chuàng)建到銷毀的一段時(shí)間,生存期的長(zhǎng)短取決于變量的存儲(chǔ)類別,也就是它所在的內(nèi)存區(qū)域。

auto 變量

auto 是自動(dòng)或默認(rèn)的意思,很少用到,因?yàn)樗械淖兞磕J(rèn)就是 auto 的。也就是說,定義變量時(shí)加不加 auto 都一樣,所以一般把它省略,不必多此一舉。

例如:

  • int n = 10;
  • auto int n = 10;
  • 的效果完全一樣。

    6. C語言extern變量和函數(shù)

    在所有的代碼塊(函數(shù)、if 塊、switch 塊等)之外定義的變量稱為全局變量,它的作用范圍默認(rèn)是整個(gè)程序,也就是所有的源文件,包括 .c 和 .h 文件。

    如果你一直在編寫單個(gè) .c 文件的程序,那么請(qǐng)注意,全局變量的作用范圍不是從變量定義處到該文件結(jié)束,在其他文件中也有效。

    雖然全局變量的作用范圍是整個(gè)程序,但是如果希望在 a.c 中使用 b.c 中的變量,也必須先進(jìn)行聲明。聲明使用 extern 關(guān)鍵字,請(qǐng)看下面的代碼。

    a.c 源碼:

    1 #include <stdio.h> 2 #include <stdlib.h> 3 extern int num; // 必須對(duì) num 進(jìn)行聲明 4 int main () 5 { 6 printf("num = %d", num); 7 system("pause"); 8 return 0; 9 }

    b.c 源碼:

    1 int num = 100; // 對(duì) num 進(jìn)行定義

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

    我們?cè)?b.c 中定義了一個(gè)全局變量 num,在 a.c 中調(diào)用了它。extern int num; 的作用是告訴編譯器 num 不在 a.c 中,請(qǐng)到其他文件中查找。如果沒有 extern,編譯器就會(huì)在當(dāng)前文件中查找,發(fā)現(xiàn)沒有就會(huì)報(bào)錯(cuò)。

    提示:編譯是針對(duì)單個(gè)源文件的,在編譯 a.c 時(shí)編譯器找不到 num,鏈接時(shí)才會(huì)在 b.c 的目標(biāo)代碼(.obj 文件)中找到 num。

    與其他變量不同,extern 變量有聲明和定義之分。

    extern 變量的定義格式為:

  • extern type name = value;
  • 不過 extern 可以省略(我們通常就是這么做的),全局變量默認(rèn)就是 extern 的,如 b.c 文件所示。

    聲明格式為:

  • extern type name;

  • 注意:

    • 在定義 extern 變量時(shí)不能省略 value,否則就變成了變量聲明。
    • 聲明 extern 變量時(shí)要指明數(shù)據(jù)類型(必須和定義時(shí)的數(shù)據(jù)類型一致)。
    • 聲明可以有多次,定義只能有一次。


    在 a.c 中,我們?cè)谒写a塊外部對(duì) num 進(jìn)行了聲明,這個(gè)時(shí)候 num 的作用范圍是 a.c 整個(gè)文件(確切的說是從聲明開始處到文件結(jié)束)。如果在代碼塊內(nèi)部聲明會(huì)怎樣呢?

    對(duì) a.c 進(jìn)行更改:

    1 #include <stdio.h> 2 #include <stdlib.h> 3 int main () 4 { 5 { 6 extern int num; 7 printf("num = %d", num); 8 } 9 printf("num = %d", num); 10 system("pause"); 11 return 0; 12 }

    編譯時(shí)報(bào)錯(cuò),第 9 行的 num 未聲明。這說明 extern 變量的作用域跟它的聲明位置有關(guān),在代碼塊內(nèi)聲明的 extern 變量在代碼塊外無效。

    extern 函數(shù)

    從本質(zhì)上講,函數(shù)和變量是類似的,它們都指向內(nèi)存中的一塊區(qū)域:函數(shù)指向存放了函數(shù)體二進(jìn)制代碼的程序代碼區(qū),變量指向靜態(tài)數(shù)據(jù)區(qū)、棧區(qū)或堆區(qū)。

    extern 除了用于變量,也可以用于函數(shù),請(qǐng)看下面的代碼:

    sum.c 源碼:

    1 int sum(int n1, int n2) 2 { 3 return n1 + n2; 4 }

    main.c 源碼:

    1 #include <stdio.h> 2 #include <stdlib.h> 3 extern int sum(int, int); 4 int main () 5 { 6 int num1 = 20, num2 = 110; 7 printf("%d + %d = %d", num1, num2, sum(num1, num2)); 8 system("pause"); 9 return 0; 10 }

    運(yùn)行結(jié)果:
    20 + 110 = 130

    我們?cè)?sum.c 中定義了一個(gè)函數(shù) sum() 用來計(jì)算兩個(gè)數(shù)的和,在 main.c 中對(duì)函數(shù)進(jìn)行了調(diào)用。extern 的作用是告訴編譯器 sum() 函數(shù)不在 main.c 中,請(qǐng)到其他文件中去查找。

    但是,函數(shù)和變量的聲明有所不同,對(duì)于函數(shù),你可以省略 extern。例如將 main.c 中的:

  • extern int sum(int, int);
  • 改為:

  • int sum(int, int);
  • 仍然能夠編譯通過并正確運(yùn)行。

    這是因?yàn)?#xff0c;函數(shù)的定義和聲明區(qū)別很明顯,有函數(shù)體就是定義,沒有函數(shù)體就是聲明,所以有沒有 extern 都是函數(shù)聲明。但是變量不一樣,沒有 extern 就是變量定義,重復(fù)定義是錯(cuò)誤的。

    ?

    ?7.?C語言static變量和函數(shù)

    上一節(jié)我們講到,全局變量和函數(shù)的作用范圍默認(rèn)是整個(gè)程序,也就是所有的源文件。這給我們帶來了很大的方便,讓我們能夠在 A 文件中調(diào)用 B 文件中定義的變量和函數(shù),不必把所有的代碼都集中到一個(gè)文件,有利于模塊化的程序設(shè)計(jì)。

    但是有時(shí)候這也會(huì)帶來沖突,例如在 a.c 中定義了一個(gè)全局變量 n,在 b.c 中又定義了一次,編譯時(shí)就會(huì)發(fā)生重復(fù)定義的錯(cuò)誤,因?yàn)樽兞恐荒芏x一次。

    如果兩個(gè)文件都是我們自己編寫的或者其中一個(gè)是,遇到這樣的情況還比較好處理,改變變量的名字就可以;但如果兩個(gè)文件都是其他程序員編寫的,或者是第三方的庫,修改起來就頗費(fèi)精力了。所以,實(shí)際開發(fā)中我們一般將不需要被其他文件調(diào)用的全局變量或函數(shù)的作用范圍限制在當(dāng)前文件中。

    可以通過 static 關(guān)鍵字來限制,請(qǐng)看下面的代碼。

    a.c 源碼:

    1 #include <stdio.h> 2 static int n = 10; 3 void print_n_a() 4 { 5 printf("n(a.c) = %d\n", n); 6 }

    b.c 源碼:

    1 #include <stdio.h> 2 static int n = 20; 3 void print_n_b() 4 { 5 printf("n(b.c) = %d\n", n); 6 }

    main.c 源碼:

    1 #include <stdio.h> 2 #include <stdlib.h> 3 int n = 100; 4 int main () 5 { 6 print_n_a(); 7 print_n_b(); 8 printf("n(main.c) = %d\n", n); 9 system("pause"); 10 return 0; 11 }

    運(yùn)行結(jié)果:
    n(a.c) = 10
    n(b.c) = 20
    n(main.c) = 100

    我們?cè)?a.c、b.c 和 main.c 中都定義了變量 n,a.c 和 b.c 中的變量 n 都只在各自的文件內(nèi)有效,main.c 中的變量 n 在整個(gè)程序內(nèi)有效。

    由此可見,加了 static 的變量或函數(shù)的作用范圍僅限于當(dāng)前文件,對(duì)其他源文件隱藏,利用這一特性可以在不同的文件中定義同名的變量或函數(shù),而不必?fù)?dān)心命名沖突。

    static 局部變量

    static 聲明的變量稱為靜態(tài)變量,不管是全局變量還是局部變量,都存儲(chǔ)在靜態(tài)數(shù)據(jù)區(qū)(全局變量本來就存儲(chǔ)在靜態(tài)數(shù)據(jù)區(qū),即使不加 static)。

    靜態(tài)數(shù)據(jù)區(qū)的數(shù)據(jù)在程序啟動(dòng)時(shí)就會(huì)初始化,直到程序運(yùn)行結(jié)束;對(duì)于代碼塊中的靜態(tài)局部變量,即使代碼塊執(zhí)行結(jié)束,也不會(huì)銷毀。

    注意:靜態(tài)數(shù)據(jù)區(qū)的變量只能初始化(定義)一次,以后只能改變它的值,不能再被初始化,即使有這樣的語句,也無效。

    請(qǐng)看下面的代碼:

    1 #include <stdio.h> 2 #include <stdlib.h> 3 int main () 4 { 5 int result, i; 6 for(i = 1; i<=100; i++) 7 { 8 result = sum(i); 9 } 10 printf("1+2+3+...+99+100 = %d\n", result); 11 system("pause"); 12 return 0; 13 } 14 int sum(int n) 15 { 16 // 也可以不賦初值 0,靜態(tài)數(shù)據(jù)區(qū)的變量默認(rèn)初始化為 0 17 static int result = 0; 18 result += n; 19 return result; 20 }

    運(yùn)行結(jié)果:
    1+2+3+...+99+100 = 5050

    我們?cè)?sum() 中定義了一個(gè)靜態(tài)局部變量 result,它存儲(chǔ)在靜態(tài)數(shù)據(jù)區(qū),sum() 函數(shù)執(zhí)行結(jié)束也不會(huì)銷毀,下次調(diào)用繼續(xù)有效。靜態(tài)數(shù)據(jù)區(qū)的變量只能初始化一次,第一次調(diào)用 sum() 時(shí)已經(jīng)對(duì) result 進(jìn)行了初始化,所以再次調(diào)用時(shí)就不會(huì)初始化了,也就是說 static int result = 0; 語句無效。

    靜態(tài)局部變量雖然存儲(chǔ)在靜態(tài)數(shù)據(jù)區(qū),但是它的作用域僅限于定義它的代碼塊,sum() 中的 result 在函數(shù)外無效,與 main() 中的 result 不沖突,除了變量名一樣,沒有任何關(guān)系。

    總結(jié)起來,static 變量的主要作用有兩個(gè)。

    1) 隱藏

    程序有多個(gè)源文件時(shí),將全局變量或函數(shù)的作用范圍限制在當(dāng)前文件,對(duì)其他文件隱藏。

    2) 保持變量?jī)?nèi)容的持久化

    將局部變量存儲(chǔ)到靜態(tài)數(shù)據(jù)區(qū)。靜態(tài)數(shù)據(jù)區(qū)的內(nèi)存在程序啟動(dòng)時(shí)就已分配好(內(nèi)存中所有的字節(jié)默認(rèn)值都是0x00),直到程序運(yùn)行結(jié)束。

    ?

    8. C語言register變量

    一般情況下,變量的值是存儲(chǔ)在內(nèi)存中的,CPU 每次使用數(shù)據(jù)都要從內(nèi)存中讀取。如果有一些變量使用非常頻繁,從內(nèi)存中讀取就會(huì)消耗很多時(shí)間,例如 for 循環(huán)中的增量控制:

    1 int i; 2 for(i=0; i<1000; i++) 3 { 4 // Some Code 5 }

    執(zhí)行這段代碼,CPU 為了獲得 i,會(huì)讀取 1000 次內(nèi)存。

    為了解決這個(gè)問題,可以將使用頻繁的變量放在CPU的通用寄存器中,這樣使用該變量時(shí)就不必訪問內(nèi)存,直接從寄存器中讀取,大大提高程序的運(yùn)行效率。

    寄存器、緩存、內(nèi)存

    為了加深對(duì) register 變量的理解,這里有必要講一下CPU寄存器。

    按照與CPU的遠(yuǎn)近來分,離CPU最近的是寄存器,然后是緩存,最后是內(nèi)存。

    寄存器是最貼近CPU的,而且CPU只在寄存器中進(jìn)行存取。寄存的意思是暫時(shí)存放數(shù)據(jù),不用每次都從內(nèi)存中取,它是一個(gè)臨時(shí)的存放數(shù)據(jù)的空間。

    而寄存器的數(shù)據(jù)又來源于內(nèi)存,于是 CPU <-- 寄存器 <-- 內(nèi)存,這就是它們之間的信息交換。

    那么為什么還需要緩存呢?因?yàn)槿绻l繁地操作內(nèi)存中同一地址上的數(shù)據(jù)會(huì)影響速度,于是就在寄存器和內(nèi)存之間設(shè)置一個(gè)緩存,把使用頻繁的數(shù)據(jù)暫時(shí)保存到緩存,如果寄存器需要讀取內(nèi)存中同一地址上的數(shù)據(jù),就不用大老遠(yuǎn)地再去訪問內(nèi)存,直接從緩存中讀取即可。

    緩存的速度遠(yuǎn)高于內(nèi)存,價(jià)格也是如此。

    注意:緩存的容量是有限的,寄存器只能從緩存中讀取到部分?jǐn)?shù)據(jù),對(duì)于使用不是很頻繁的數(shù)據(jù),會(huì)繞過緩存,直接到內(nèi)存中讀取。所以不是每次都能從緩存中得到數(shù)據(jù),這就是緩存的命中率,能夠從緩存中讀取就命中,否則就沒命中。

    關(guān)于緩存的命中率又是一門學(xué)問,哪些數(shù)據(jù)保留在緩存,哪些數(shù)據(jù)不保留,都有復(fù)雜的算法。


    注意:上面所說的CPU是指CPU核心,從市場(chǎng)上購買的CPU已是封裝好的套件,附帶了寄存器和緩存,插到主板上就可以用。

    從經(jīng)濟(jì)和速度的綜合考慮,緩存又被分為一級(jí)緩存、二級(jí)緩存和三級(jí)緩存,它們的存取速度和價(jià)格依次降低,容量依次增加。購買到的CPU一般會(huì)標(biāo)出三級(jí)緩存的容量。

    register 變量

    寄存器的數(shù)量是有限的,通常是把使用最頻繁的變量定義為 register 的。

    來看一個(gè)計(jì)算 π 的近似值的例子,求解的一個(gè)近似公式如下:


    為了提高精度,循環(huán)的次數(shù)越多越好,可以將循環(huán)的增量控制定義為寄存器變量,如下所示:

    1 #include <stdio.h> 2 #include <conio.h> 3 int main() 4 { 5 register int i = 0; // 寄存器變量 6 double sign = 1.0, res = 0, ad = 1.0; 7 for(i=1; i<=100000000; i++) 8 { 9 res += ad; 10 sign=-sign; 11 ad=sign/(2*i+1); 12 } 13 res *= 4; 14 printf("pi is %f", res); 15 getch(); 16 return 0; 17 }

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

    關(guān)于寄存器變量有以下事項(xiàng)需要注意:
    1) 為寄存器變量分配寄存器是動(dòng)態(tài)完成的,因此,只有局部變量和形式參數(shù)才能定義為寄存器變量。

    2) 局部靜態(tài)變量不能定義為寄存器變量,因?yàn)橐粋€(gè)變量只能聲明為一種存儲(chǔ)類別。

    3) 寄存器的長(zhǎng)度一般和機(jī)器的字長(zhǎng)一致,所以,只有較短的類型如int、char、short等才適合定義為寄存器變量,諸如double等較大的類型,不推薦將其定義為寄存器類型。

    4) CPU的寄存器數(shù)目有限,因此,即使定義了寄存器變量,編譯器可能并不真正為其分配寄存器,而是將其當(dāng)做普通的auto變量來對(duì)待,為其分配棧內(nèi)存。當(dāng)然,有些優(yōu)秀的編譯器,能自動(dòng)識(shí)別使用頻繁的變量,如循環(huán)控制變量等,在有可用的寄存器時(shí),即使沒有使用 register 關(guān)鍵字,也自動(dòng)為其分配寄存器,無須由程序員來指定。

    ?

    轉(zhuǎn)載于:https://www.cnblogs.com/chunlanse2014/articles/4422153.html

    總結(jié)

    以上是生活随笔為你收集整理的动态内存分配及变量存储类别(第二部分)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。