欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語(yǔ)言中儲(chǔ)存類別與內(nèi)存管理的深入理解

 更新時(shí)間:2021年03月08日 10:11:52   作者:黑尾鷗  
這篇文章主要給大家介紹了關(guān)于C語(yǔ)言中儲(chǔ)存類別與內(nèi)存管理的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

儲(chǔ)存類別

C語(yǔ)言提供了多種儲(chǔ)存類別供我們使用,并且對(duì)應(yīng)的有對(duì)應(yīng)的內(nèi)存管理策略,在了解C中的儲(chǔ)存類型前,我們先了解一下與儲(chǔ)存類型相關(guān)的一些概念。

1. 基礎(chǔ)概念

對(duì)象:不同于面向?qū)ο缶幊讨械膶?duì)象的含義,C語(yǔ)言是面向過程編程,不存在這樣對(duì)象的概念,這個(gè)對(duì)象指的是值儲(chǔ)存所占據(jù)物理內(nèi)存空間。

左值:左值是可以指定對(duì)象的表達(dá)式,它的最簡(jiǎn)單形式即為標(biāo)識(shí)符,復(fù)雜的可以為為指針之類。一個(gè)表達(dá)式成為左值的前提是它確實(shí)指定了一塊作為對(duì)象的儲(chǔ)存空間,例如:

 int a = 1;//a作為標(biāo)識(shí)符,也作基礎(chǔ)表達(dá)式,指定了一個(gè)對(duì)象,是左值
 int *pa = &a;//pa同a也指示了一個(gè)儲(chǔ)存地址對(duì)象,是一個(gè)左值;*pa是一個(gè)表示式,指示了a相同的對(duì)象也是一個(gè)左值
 int arr[5] = {0};
 arr+a*3;// 這段表達(dá)式就不是一個(gè)標(biāo)識(shí)符,也不是一個(gè)左值了,因?yàn)樗鼪]有指定內(nèi)存上的任意位置
 *(arr + a * 3);// 不同于上面的,這也是一個(gè)左值,因?yàn)樗_實(shí)指定了內(nèi)存上的位置

左值分為可修改左值和不可修改左值。

我們通常用儲(chǔ)存期來描述對(duì)象,表明對(duì)象在內(nèi)存中留存的時(shí)間。用標(biāo)識(shí)符指定對(duì)象時(shí),使用作用域和鏈接來描述標(biāo)識(shí)符,其中作用域表明標(biāo)識(shí)符可以可以被程序使用的范圍,鏈接表明程序的哪些其他文件也可以使用它。

不同的儲(chǔ)存類別之間的區(qū)別即在于它們的儲(chǔ)存期、作用域和連接形式的不相同。我們來分別了解他們一下。

儲(chǔ)存期:儲(chǔ)存期分為靜態(tài)儲(chǔ)存期,自動(dòng)儲(chǔ)存期,線程儲(chǔ)存期和動(dòng)態(tài)分配儲(chǔ)存期(線程儲(chǔ)存期暫時(shí)不多贅述),它們分別對(duì)應(yīng)不同的在內(nèi)存中的儲(chǔ)存位置,也有不同的特點(diǎn)。

靜態(tài)儲(chǔ)存期:對(duì)應(yīng)靜態(tài)存儲(chǔ)位置,它在程序開始運(yùn)行時(shí)就被分配,這段空間不可增加和減少,所以從程序開始運(yùn)行到停止運(yùn)行,靜態(tài)儲(chǔ)存期的數(shù)據(jù)一直存在。通常在函數(shù)外的變量和static表示的變量具有靜態(tài)儲(chǔ)存期。

自動(dòng)儲(chǔ)存期:對(duì)應(yīng)??臻g,它隨著程序的運(yùn)行可以自動(dòng)進(jìn)行分配,增加或減少。程序進(jìn)入到一個(gè)塊為其中的變量分配??臻g,退出一個(gè)塊后則會(huì)釋放相應(yīng)的空間。一般的創(chuàng)建的變量都具有自動(dòng)儲(chǔ)存期。

動(dòng)態(tài)分配儲(chǔ)存期:對(duì)應(yīng)堆空間,它需要通過特殊的語(yǔ)法進(jìn)行申請(qǐng),申請(qǐng)后也需要主動(dòng)進(jìn)行銷毀,存在時(shí)間為從申請(qǐng)內(nèi)存開始到主動(dòng)釋放內(nèi)存為止。需要通過專門的語(yǔ)句來獲得具有動(dòng)態(tài)分配儲(chǔ)存期的變量。

作用域:一個(gè)變量能被使用的范圍稱為作用域,作用域分為 塊作用域、函數(shù)作用域、函數(shù)原型作用域和 文件作用域。

塊作用域:由一個(gè)花括號(hào)開始到與之對(duì)應(yīng)的花括號(hào)為止,其中的變量都具有塊作用域,一般情況下任何在塊內(nèi)的定義的變量可以在塊內(nèi)任何位置使用,但是不可以在塊外進(jìn)行使用。(特例后面會(huì)舉出),而且對(duì)于內(nèi)部塊也可以定義與外部塊同名的變量,這時(shí)候內(nèi)部塊將隱去向內(nèi)隱去外部塊的同名變量,在內(nèi)部使用自己定義的該變量。

函數(shù)作用域:針對(duì)的是goto語(yǔ)句標(biāo)簽,一個(gè)標(biāo)簽首次出現(xiàn)在含糊內(nèi)層,它的作用域?qū)?huì)延伸至整個(gè)函數(shù),這表示我們不能使用同名的標(biāo)簽。

函數(shù)原型作用域:對(duì)于函數(shù)的聲明,該作用域開始與形參定義處知道函數(shù)函數(shù)原型結(jié)束。編譯器只注重形式參數(shù)的類型而不會(huì)注意具體的變量名,甚至可以不使用變量名。

文件作用域:聲明在函數(shù)外的變量具有文件作用域,他們可以在同一源文件下的任何塊和函數(shù)中使用,具有文件作用域的變量也被稱為全局變量。

對(duì)于分別屬于同類型作用域但是不同一個(gè)作用域的變量它們可以任意重名,例如不同塊的函數(shù)中變量屬于不同塊他們可以重名。對(duì)于具有文件作用域的變量它們對(duì)于所屬的文件塊都有作用,所以不建議塊中變量與全局變量重名,但是在重名后塊使用對(duì)應(yīng)名稱變量時(shí)將以塊中自身定義的變量為準(zhǔn)。

 #include <stdio.h>
 ​
 void showA(int a, int type) {
 switch (type) {
 case 1:
 printf("outer : ");
 break;
 case 2:
 printf("inter : ");
 break;
 case 3:
 printf("circle : ");
 default:
 ;
 }
 printf("a = %d\n", a);
 }
 ​
 int main (void) {
 int a = 1;
 showA(a, 1);
 {
 int a = 2;
 showA(a, 2);
 }
 showA(a, 1);
 while (a++ < 5) {
 int a = 5;
 showA(a, 3);
 }
 showA(a, 1);
 return 0;
 }
 ​
 ​
 /**
 outer : a = 1
 inter : a = 2
 outer : a = 1
 circle : a = 5
 circle : a = 5
 circle : a = 5
 circle : a = 5
 outer : a = 6
 * **/

我們發(fā)現(xiàn)在在外部a為在外部定義的值,a輸出為1;第一塊內(nèi)部,a讀取的是內(nèi)部的a的值,這一點(diǎn)沒有任何問題;然后我們到外部,我們?cè)僮尦绦蜉敵鯽值,仍然為2,沒有問題;但是進(jìn)入循環(huán)后,我們發(fā)現(xiàn)很奇怪的現(xiàn)象,通過輸出我們發(fā)現(xiàn)循環(huán)執(zhí)行了4次,很明顯這是基于外部的a,但是內(nèi)部的a在輸出時(shí)卻總是顯示內(nèi)部的a,這一點(diǎn)是因?yàn)椋簝?nèi)部循環(huán)定義的a作用域只在塊內(nèi),并不會(huì)作用于循環(huán)條件判斷的部分,所以在進(jìn)行循環(huán)條件判斷時(shí)始終使用外部的a。注意遞增條件一定要在循環(huán)判斷條件中,否則循環(huán)將變成死循環(huán)。但是,沒有必要使用同名變量。

鏈接:鏈接是程序中變量可以被其他文件使用的描述,有三種類型的鏈接:外部鏈接、內(nèi)部鏈接和 無(wú)鏈接。

如果一個(gè)變量具有文件作用域它才可能具有外部鏈接和內(nèi)部鏈接,其他變量都是無(wú)鏈接的。在具體了解內(nèi)部鏈接和外部鏈接之前,我們先理解下 翻譯單元的概念。

翻譯單元:我們經(jīng)常使用#include指令來包含頭文件,C通過預(yù)處理將對(duì)應(yīng)頭文件內(nèi)容直接替換掉該條命令,他們雖然表面上看起來不是一個(gè)文件但是被編譯器看做了一個(gè)文件,這個(gè)文件就被稱為一個(gè)翻譯單元,一個(gè)具有文件作用域的變量它的實(shí)際可見范圍就是整個(gè)翻譯單元。一個(gè)翻譯單元由一個(gè)源文件和多個(gè)它所包含的文件組成。

所以外部鏈接可以在多文件程序中使用,而內(nèi)部鏈接只可以在一個(gè)翻譯單元使用。區(qū)別二者在于是否使用了儲(chǔ)存類別說明符static,使用了static則為內(nèi)部鏈接,反之則為外部鏈接。

 //main.c 文件
 #include <stdio.h>
 ​
 int main (void) {
 extern int a;// 聲明,讓編譯器在別處查找a的定義
 // extern int b;
 // printf("b = %d", b);這一段不可使用,因?yàn)閎只具有內(nèi)部鏈接,不可在其他源文件訪問,運(yùn)行
 // 報(bào)錯(cuò)
 printf("a = %d", a);
 return 0;
 }
 ​
 /**
 a = 5
 * **/
 // 和它一同編譯的another.c文件
 int a = 5;// 具有外部鏈接,可以在多個(gè)源文件之間進(jìn)行共享
 static int b = 2;// 具有內(nèi)部鏈接,只能在一個(gè)源文件內(nèi)共享

在這里我們使用了外部鏈接變量a,在兩個(gè)翻譯單元之間實(shí)現(xiàn)了變量的傳遞。其中main.c文件為了調(diào)用變量a必須有extern聲明語(yǔ)句,這段語(yǔ)句聲明了一個(gè)int型變量a但是并不會(huì)為它分配內(nèi)存,使用它只是為了告訴編譯器在別處尋找變量a的定義,這是必不可少的,否則程序?qū)?huì)報(bào)錯(cuò)。

 // main.c文件
 #include <stdio.h>
 #include "main.h"
 ​
 int main (void) {
 extern int a;
 printf("a = %d", a);
 return 0;
 }
 ​
 /**
 a = 7
 * **/
 // main.h文件
 static int a = 7;

不同于源文件,對(duì)于頭文件,通過#include指令包含頭文件,編譯器將自動(dòng)將對(duì)應(yīng)文件內(nèi)容替代到對(duì)應(yīng)位置,它們屬于同一個(gè)翻譯單元,所以及時(shí)具有內(nèi)部鏈接的變量仍可以使用。

2. 儲(chǔ)存類別分類

介紹了一些基礎(chǔ)概念后我們來根據(jù)這些基礎(chǔ)概念對(duì)于儲(chǔ)存類別進(jìn)行分類:

儲(chǔ)存類別 儲(chǔ)存期 作用域 鏈接 聲明方式
自動(dòng) 自動(dòng) 無(wú) 塊內(nèi)聲明
寄存器 自動(dòng) 無(wú) 塊內(nèi)聲明,加入關(guān)鍵字register
靜態(tài)外部鏈接 靜態(tài) 文件 外部 函數(shù)外
靜態(tài)內(nèi)部鏈接 靜態(tài) 文件 內(nèi)部 函數(shù)外,加入關(guān)鍵字static
靜態(tài)無(wú)鏈接 靜態(tài) 無(wú) 塊內(nèi)聲明,計(jì)入關(guān)鍵字static

下面我呢來分別具體對(duì)于每種類型所對(duì)應(yīng)的變量進(jìn)行說明。

3. 自動(dòng)變量

自動(dòng)變量具有自動(dòng)儲(chǔ)存期,塊作用域,無(wú)鏈接,在塊內(nèi)進(jìn)行聲明即可。自動(dòng)儲(chǔ)存期意味著它在開始執(zhí)行塊時(shí)被創(chuàng)建,在對(duì)應(yīng)塊到結(jié)尾時(shí)被銷毀,不能再被通過任何途徑訪問;塊作用域表明只能在塊中使用變量名對(duì)于變量進(jìn)行訪問,但是在處于變量可使用的儲(chǔ)存期內(nèi)(這點(diǎn)必要,因?yàn)槲覀儫o(wú)法控制編譯器的回收機(jī)制),我們也可以通過指針傳遞地址的方式來繼續(xù)使用;無(wú)鏈接表明不能再其他文件中對(duì)于該變量進(jìn)行訪問。

對(duì)于自動(dòng)變量,默認(rèn)情況下聲明的變量都具有這樣的儲(chǔ)存類別,但是有時(shí)候?yàn)榱烁黠@的表現(xiàn)意圖,并且在外部具有同名變量時(shí),為了更好覆蓋它,表明自己變量的自動(dòng)儲(chǔ)存類型,可以使用關(guān)鍵字auto,例如:

 #include <stdio.h>
 ​
 int a = 1;
 ​
 int main (void) {
 auto int a;// int a;也是等價(jià)
 printf("a = %d", a);
 return 0;
 }

在外部有同名變量時(shí),使用auto關(guān)鍵字還是用來標(biāo)識(shí)a作為塊內(nèi)的自動(dòng)變量,覆蓋外部的a,即使不加auto也是可以的,但是使用后可以起到更好的標(biāo)識(shí)性。

4. 寄存器變量

寄存器變量在多個(gè)方面與自動(dòng)變量相同,不同在于自動(dòng)變量通常儲(chǔ)存在計(jì)算機(jī)內(nèi)存中,而寄存器變量?jī)?chǔ)存在計(jì)算機(jī)CPU的寄存器中,因此它具有高效的運(yùn)算率,而且因?yàn)樗诩拇嫫髦兴詿o(wú)法獲得其地址。通過在變量定義中使用register修飾既可以聲明寄存器變量:register int a;

但是,值得注意的是,使用register企圖創(chuàng)建寄存器變量是一種請(qǐng)求而不是命令,編譯器很可能不會(huì)通過你的請(qǐng)求,而且寄存器也有可能沒有足夠大空間儲(chǔ)存double類型變量,所以可以聲明register的數(shù)據(jù)類型也是有限的。即使失敗,也能夠創(chuàng)建相應(yīng)的自動(dòng)變量,但是我們?nèi)匀徊荒塬@得其地址。

5. 具有塊作用域的靜態(tài)變量

具有塊作用域的靜態(tài)變量,對(duì)應(yīng)的儲(chǔ)存類別為靜態(tài)無(wú)鏈接,其具有靜態(tài)儲(chǔ)存期,塊作用域和無(wú)鏈接。它在程序開始運(yùn)行時(shí)被創(chuàng)建,程序結(jié)束后被銷毀。只在它被定義的塊內(nèi)調(diào)用,無(wú)法被其他文件訪問。

相較于自動(dòng)變量,它只是擁有了靜態(tài)儲(chǔ)存期,所以我們使用static類別修飾符獲得該類型變量static int a;。值得注意的是,由于該變量具有靜態(tài)儲(chǔ)存期,所以它始終儲(chǔ)存在系統(tǒng)中的某一段內(nèi)存空間中,我們可以利用指針在塊外的區(qū)域?qū)τ谠撟兞窟M(jìn)行訪問。

 #include <stdio.h>
 ​
 int* fun();
 ​
 int main (void) {
 int *p = fun();
 *p += 2;
 fun();
 return 0;
 }
 ​
 int *fun() {
 static int a = 1;
 printf("a = %d\n", a);
 return &a;
 }
 ​
 /**
 a = 1
 a = 3
 * **/

通過上面的運(yùn)行結(jié)果我們發(fā)現(xiàn)通過函數(shù)返回指向靜態(tài)變量的指針,我們可以對(duì)靜態(tài)變量進(jìn)行訪問和修改,這使得我們?cè)趬K外對(duì)塊內(nèi)無(wú)鏈接的靜態(tài)變量進(jìn)行訪問。

6. 內(nèi)部鏈接的靜態(tài)變量

內(nèi)部鏈接的靜態(tài)變量對(duì)應(yīng)儲(chǔ)存類別為靜態(tài)內(nèi)部鏈接。它具有靜態(tài)作用期,文件作用域和內(nèi)部鏈接。它在程序開始被創(chuàng)建,在同一個(gè)翻譯單元內(nèi)可以任意訪問。在前面已經(jīng)有它的用例。

7. 外部鏈接的靜態(tài)變量

外部鏈接的靜態(tài)變量對(duì)應(yīng)儲(chǔ)存類別為靜態(tài)外部鏈接。它具有靜態(tài)作用器,文件作用域和外部鏈接。大體上與內(nèi)部鏈接的靜態(tài)變量相同,但是它可以在多個(gè)翻譯單元(多個(gè)源文件之間)進(jìn)行共享。

但是仍有一些事項(xiàng)注意:

聲明時(shí)可以顯示初始化,但是必須使用常量進(jìn)行初始化(對(duì)于sizeof表達(dá)式也是常量),如果未進(jìn)行初始化,無(wú)論如何它將被初始化為0。

 #include <stdio.h>
 ​
 int a;
 int b = 3;
 int c = 3 * sizeof b;
 // int d = 3 * a;非常量無(wú)法初始化
 char d;
 ​
 int main (void ) {
 printf("a = %d\n", a);
 printf("b = %d\n", b);
 printf("c = %d\n", c);
 printf("d = %d d = %c\n", d, d);
 return 0;
 }
 ​
 /**
 a = 0
 b = 3
 c = 12
 d = 0 d =
 * **/

如何跨文件使用具有外部鏈接的變量?正常情況下直接使用將會(huì)報(bào)錯(cuò),我們需要通過引用性聲明來使用,通過extern關(guān)鍵字來實(shí)現(xiàn),在變量聲明前加上關(guān)鍵字,編譯器就會(huì)明白根據(jù)指示在其他源文件中查找變量的聲明,這樣的聲明不會(huì)申請(qǐng)新的內(nèi)存,也不可以進(jìn)行賦值。

 // main.c
 #include <stdio.h>
 ​
 int main (void ) {
 // extern int a = 1;是不能賦值的
 extern int a;
 printf("a = %d\n", a);
 return 0;
 }
 ​
 /**
 a = 5
 * **/
 // anothor.c
 int a = 5;

8. 儲(chǔ)存類別說明符小結(jié)

C中儲(chǔ)存類別說明符有多個(gè),并且不同說明符在不同位置也有不同意義。一共有一下說明符:auto、extern、register、static、_Thread_local和typedef。最后者被歸為此類屬于一些語(yǔ)法上的原因。它們大多都是單獨(dú)使用,但是_Thread_local可以和static和extern一起使用。

auto表明變量具有自動(dòng)儲(chǔ)存期,在塊內(nèi)的變量默認(rèn)具有自動(dòng)儲(chǔ)存期,使用auto只是明確表示要使用與外部變量重名的局部變量的意圖。

register表明希望將變量?jī)?chǔ)存在寄存器中,希望以最快的速度讀取變量,同時(shí)不希望獲得該變量的地址。

static表明變量具有靜態(tài)儲(chǔ)存期,它并不改變塊內(nèi)變量的鏈接類型,但是對(duì)于快外的變量,將會(huì)限制它的鏈接類型為內(nèi)部鏈接。

extern表明該變量定義在別處,希望編譯器在別處查找,包含extern的聲明具有文件作用域,那么變量的定義一定有外部鏈接;如果只是具有塊作用域,那么變量的定義可以有內(nèi)部鏈接,也可以外部鏈接。

9. 儲(chǔ)存類別的選用

到最后了,我們來考慮下儲(chǔ)存類比的選用,一般情況下我們只建議使用自動(dòng)儲(chǔ)存類別,使用外部變量在程序間通信是方便的但同時(shí)也是危險(xiǎn)的,所以我們希望盡力避免使用,同時(shí)我們要明白保護(hù)性程序設(shè)計(jì)的“按需知道”法則,盡量在函數(shù)內(nèi)部解決該函數(shù)的任務(wù),只共享哪些必須共享的變量。

動(dòng)態(tài)內(nèi)存管理

C語(yǔ)言除了自身建立了自動(dòng)儲(chǔ)存類型和靜態(tài)儲(chǔ)存類型來進(jìn)行自主的內(nèi)存管理來方便我們編程,同時(shí)也給我提供了一些工具是的我們能夠進(jìn)行靈活的內(nèi)存使用和管理,我們通過了解使用C語(yǔ)言的內(nèi)存分配來具體了解。

1. 內(nèi)存分配之malloc

malloc函數(shù)聲明在頭文件stdlib.h中,其函數(shù)原型為

void* malloc(size_t size);

我們通過參數(shù)size(單位字節(jié))來獲得指定大小的一段空間同時(shí)返回指向該空間的空指針,我們可以通過強(qiáng)制類型轉(zhuǎn)換來獲得我們需要類型的指針,如果申請(qǐng)內(nèi)存失敗,它就會(huì)返回空指針NULL。我們通過具體的用例來了解它的使用:

 #include <stdio.h>
 #include <stdlib.h>
 ​
 int main (void) {
 int *a = (int *)malloc(sizeof(int));// 創(chuàng)建一個(gè)int
 int *b = (int *)malloc(sizeof(int)*5);// 創(chuàng)建長(zhǎng)度為5的數(shù)組
 *a = 4;
 for (int i = 0; i < 5; ++i)
  b[i] = i*i;
 printf("*a = %d\n", *a);
 for (int i = 0; i < 5; ++i)
  printf("b[%d] = %d\n", i, b[i]);
 free(a);
 free(b);
 return 0;
 }
 ​
 /**
 *a = 4
 b[0] = 0
 b[1] = 1
 b[2] = 4
 b[3] = 9
 b[4] = 16
 * **/

我們發(fā)現(xiàn)可以通過內(nèi)存申請(qǐng)可以靈活的創(chuàng)建變量和數(shù)組,然后對(duì)他們進(jìn)行訪問和修改,但是千萬(wàn)不要忘記調(diào)用free函數(shù)接受被分配空間的指針,來釋放對(duì)應(yīng)空間。不然大量的空間將無(wú)法被再利用造成內(nèi)存的浪費(fèi),同時(shí)一些操作系統(tǒng)在程序運(yùn)行結(jié)束后可能不會(huì)自動(dòng)釋放這些被分配的內(nèi)存,甚至可能耗盡內(nèi)存,產(chǎn)生可怕的 內(nèi)存泄漏。

同時(shí)通過動(dòng)態(tài)分配內(nèi)存也有更加靈活的用途,例如創(chuàng)建變長(zhǎng)數(shù)組:

 #include <stdio.h>
 #include <stdlib.h>
 ​
 int main (void) {
 int len;
 scanf("input the len: %d", &len);
 int *arr = (int *)malloc(sizeof(int) * len);
 return 0;
 }

通過這樣一段程序我們就實(shí)現(xiàn)了,創(chuàng)建用戶輸入數(shù)字大小的整形數(shù)組。

2. 內(nèi)存分配值calloc

calloc函數(shù)與malloc函數(shù)功能大體相同,它的函數(shù)原型:

void *calloc(size_t num, size_t size);

接受兩個(gè)參數(shù),第一個(gè)為希望分配的該大小的內(nèi)存塊數(shù),第二個(gè)為希望一個(gè)空間大?。▎挝蛔止?jié))。同樣的我們要求在每次使用過后通過free函數(shù)將對(duì)應(yīng)指針指向的分配的空間進(jìn)行釋放。

儲(chǔ)存類別和動(dòng)態(tài)內(nèi)存分配

儲(chǔ)存類別和內(nèi)存分配有著密切可分的關(guān)系,我們來講述一個(gè)理想中的模型:

程序?qū)⑺膬?nèi)存分為三個(gè)部分,一部分給靜態(tài)變量使用;一部分給自動(dòng)變量使用,最后一部分提供給動(dòng)態(tài)內(nèi)存分配。為什么這樣分配呢?

靜態(tài)變量使用的內(nèi)存在程序編譯時(shí)確定,在程序運(yùn)行的整個(gè)周期都可以別訪問,最后在程序結(jié)束時(shí)被銷毀,所以我們可以單獨(dú)使用一塊區(qū)域?qū)τ谄溥M(jìn)行管理。

自動(dòng)變量在進(jìn)入對(duì)應(yīng)變量定義的塊時(shí)被分配空間,在離開塊后被銷毀。伴隨著函數(shù)的調(diào)用和結(jié)束,自動(dòng)變量使用的內(nèi)存數(shù)量也對(duì)應(yīng)的增加和減少,這部分內(nèi)存通常使用棧來管理,新建的變量將按順序入棧,銷毀時(shí)按照相反的方向進(jìn)行銷毀。

使用動(dòng)態(tài)分配內(nèi)存的內(nèi)容,他們創(chuàng)建于malloc或者calloc函數(shù)被調(diào)用的時(shí)候,在調(diào)用free函數(shù)被銷毀,這些內(nèi)存完全依賴于程序員自身的管理,我們可以在一個(gè)函數(shù)中創(chuàng)建它然后在另一個(gè)函數(shù)中銷毀它。這樣就使得這樣的一部分內(nèi)存被分配的支離破碎,有可能未分配的內(nèi)存處于分配的內(nèi)存之間,使用這樣的內(nèi)存往往是比使用棧來的更慢的。

我們通過一個(gè)程序來更好了解變量處于的空間:

 #include <stdio.h>
 #include <stdlib.h>
 ​
 static int a = 1;
 static int b = 2;
 ​
 int main (void) {
 static int c = 3;
 int d = 4;
 int e = 5;
 int f = 6;
 int *p1 = (int *)malloc(sizeof(int));
 int *p2 = (int *)malloc(sizeof(int));
 int *p3 = (int *)malloc(sizeof(int));
 printf("static: %p\n", &a);
 printf("static: %p\n", &b);
 printf("static: %p\n", &c);
 printf("auto: %p\n", &d);
 printf("auto: %p\n", &e);
 printf("auto: %p\n", &f);
 printf("dynasty: %p\n", p1);
 printf("dynasty: %p\n", p2);
 printf("dynasty: %p\n", p3);
 return 0;
 }
 ​
 /**
 static: 00405004
 static: 00405008
 static: 0040500C
 auto: 0061FF10
 auto: 0061FF0C
 auto: 0061FF08
 dynasty: 00791930
 dynasty: 007918B8
 dynasty: 007918C8
 * **/

可以發(fā)現(xiàn)不同類型的變量?jī)?chǔ)存在不同地址附近。

總結(jié)

對(duì)于C中的變量我們可以通過類型和儲(chǔ)存類別來描述,除此之外C新的標(biāo)準(zhǔn)也更新了一些特殊的修飾符const之類來修飾,靈活的使用他們能讓程序運(yùn)行的更有效率,實(shí)現(xiàn)更多的功能。

到此這篇關(guān)于C語(yǔ)言中儲(chǔ)存類別與內(nèi)存管理的文章就介紹到這了,更多相關(guān)C語(yǔ)言儲(chǔ)存類別與內(nèi)存管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論