變數的儲存屬性與記憶體管理

2021-06-23 03:18:53 字數 4623 閱讀 5254

一、變數儲存屬性

變數是對程式中資料的儲存空間的抽象。因此變數的屬性包含兩個:資料型別和儲存型別。

1、資料型別

資料型別決定了資料所佔儲存空間的大小及取值範圍。

2、儲存型別

儲存型別決定了變數的作用域和生存期。

儲存型別包括4種:自動型(auto)、暫存器型(register)、靜態型(static)和

外部型(extern);

這四種

儲存型別有兩種儲存方法:靜態儲存和動態儲存。其中auto

和register為動態儲存,static和extern為靜態儲存。

2.1 自動變數(auto)

自動變數也叫區域性變數(在函式或類內部定義的變數),是指在函式內部說明的變數。

所有的非

全域性變數都被

認為是區域性變 量,所以auto實際上從來不用。區域性變數在函式

呼叫時自動產生,但不會自動初始化, 隨函式

呼叫的結束,變數自動消失,下 次呼叫

此函式時再自動產生,還要重新賦值,退出時又自動消失。

作用域:從函式定義開始,到函式體或複合體結束。

2.2 暫存器變數(register)

暫存器變數也是自動變數,只有區域性比變數、形參可以定義為register,靜態變數(全域性變數肯定是靜態變數)

不能定義為register。一般的變數都是儲存在記憶體中的,在程式需要的時候,就

把變數從記憶體中讀取到運

算器中。 在

比較關注速度時,可以使用register將變數存在操

作比記憶體快的暫存器中。值得注意的是,取位址運

算符&不

能作用於暫存器。

作用域:從函式定義開始,到函式體或複合體結束。

2.3 靜態變數(static)

靜態變數的生命週期是整個程式的一次執行過程,即值會一直保持不變(生命週期長)。但是作用範圍是被限

定的。即靜態全域性變數不能

被定義靜態全域性變數

的檔案之外的其他檔案所

引用;靜態區域性變數不能在函式外使用。

(1)靜態區域性變數  

它與區域性變數的區別在於:在函式退出時,這個變數始終存在,只是不能被其它函式使

用,當再次進入該函式時,

將儲存上次的結果。其它與區域性變數一樣。 

(2)靜態全域性變數 

靜態全域性變數就是指只在定義它的原始檔中可見而在其它原始檔中不可見的變數。它

與全域性變數的區別是:全域性

變數可以再說明為外部變數(extern),被其它原始檔使用,

而靜態全域性變數不能再被說明為外部的,即只能

被所在

原始檔使用。

2.4 外部變數(extern)

在函式之外定義的變數稱為全域性變數或外部變數。作用域為從定義變數開始到原始檔

結束。編譯時會將全域性變

量分配在靜

態儲存區。

全域性變數在下面兩種情況下需要使用extern宣告:

(1)在同乙個檔案中,若全域性變數定義在後而使用在前時,則需要在使用之前使用

extern對該變數進行外部變

量宣告。

(2)若多個檔案的程式要引用同乙個全域性變數,好的做法是:在乙個檔案中定義外

部變數,而在非定義的檔案

中使用extern對該變數作外部變數宣告。

二、記憶體管理

記憶體分配方式有三種:

(1)從靜態(全域性)儲存區域

內存在程式編譯的時候就已經分配好,這塊內

存在程式的整個執行期間都存

在,生命週期長。例如全域性變數,

static變數。

int a1;   //初始化為0

char s1; //初始化為0

static int a2; //初始化為0

static char s2; //初始化為0

void fun_test(int par)

e.g..

全域性變數a1、s1,靜態全域性變數a2、s2,靜態區域性變數a3、s3,預設初

始化為0;還有字串常

量「123456789」。

值得注意的是

靜態區域性變數a3、s3的作

用範圍為

函式fun_test內;字串常量佔據的空間是10位元組(末尾有『\0』)。

(2)棧

在執行函式時,函式內區域性變數的儲存單元都可以在棧

上建立,函式執行結

束時這些儲存單元自動被釋放。棧

記憶體分配運算內置於

處理器的指令集中,

效率很高,但是分配的記憶體容量有限。

e.g..

形參par,區域性變數(自動變數)a4、s4,指標ptr、ss。均不會自動初始化。

(3) 堆,亦稱動態記憶體分配

程式在執行的時候用malloc或new

申請任意多少的記憶體,程式設計師自己負責在

何時用free或delete釋放記憶體。動

態記憶體的生存期由我們決定,使用非常靈

活,但問題也最多。只有在堆上分

配的記憶體才需要(也必須)我們進 行釋

放,否則就會造成記憶體洩漏。

e.g..

new分配的10位元組記憶體(ss指向的記憶體區域)。

三、malloc和new的區別

1malloc和free是c++/c的標準庫函式,new和delete是c++的運算子。c++程式經常要呼叫c函式,而c程式只能呼叫malloc和new函式。

2對於非內部型別的物件而言,malloc和free無法滿足動態物件的要求。

由於malloc和free是庫函式不是運算子,不在編譯器控制許可權之內,無法在物件建立時呼叫建構函式,在物件消亡前自動呼叫析構函式;

而new是運算子,能動態完成記憶體分配和初始化的工作;delete運算子能夠完成清理和釋放記憶體的工作。

3malloc和free,以及new和delete的使用

3.1 malloc()、free()函式。int*p;

p=(int*)malloc(sizeof(int)*128); ... free(p);p=null;

3.1.1原型:extern void *malloc(unsigned int num_bytes);  e.g.. char *ptr; ptr = (char*)malloc(100);   ...   free(p);p=null;

說明:分配長度為num_bytes位元組的記憶體塊。如果分配成功則返回指向被分配記憶體的指標,分配失敗返回空指標null。當記憶體不再使用時,應使用free()函式將記憶體塊釋放。返回型別是 void* 型別。void* 表示未確定型別的指標。c,c++規定,void* 型別可以強制轉換為任何其它型別的指標。備註:void* 表示未確定型別的指標,更明確的說是指申請記憶體空間時還不知道使用者是用這段空間來儲存什麼型別的資料(比如是char還是int或者...)。雖然malloc()函式的型別是(void *),任何型別的指標都可以轉換成(void *),但是最好還是在前面進行強制型別轉換,因為這樣可以躲過一些編譯器的檢查。

3.1.2 malloc()到底從**得到了記憶體空間?

答案是從堆裡面獲得空間。也就是說函式返回的指標是指向堆裡面的一塊記憶體。作業系統中有乙個記錄空閒記憶體位址的鍊錶。當作業系統收到程式的申請時,就會遍歷該鍊錶,然後就尋找第乙個空間大於所申請空間的堆結點,然後就將該結點從空閒結點鍊錶中刪除,並將該結點的空間分配給程式。

3.2 new、delete運算子。int* parr;parr=new int[100];   ...   //delete parr; parr=0;

一旦刪除了指標所指的物件,立即將指標置為0,這樣就非常清楚的指明指標不再指向任何物件。(零值指標:int *ip=0;)

3.2.1 int *pi=new int; 這個new表示式在堆區中分配建立了乙個整型物件,並返回此物件的位址,並用該位址初始化指標pi 。

3.2.2 撤銷動態建立的物件。delete pi;//釋放單個物件   deletepi;//釋放陣列

3.3 區分零值指標和null指標

零值指標,是值是0的指標,可以是任何一種指標型別,可以是通用變體型別void*也可以是char*,int*等等。

空指標,其實空指標只是一種程式設計概念,就如乙個容器可能有空和非空兩種基本狀態,而在非空時可能裡面儲存了乙個數值是0,因此空指標是人為認為的指標不提供任何位址訊息。

4new返回指定型別的指標,並且可以自動計算所需大小;而malloc則必須由我們計算位元組數,並且在返回後強制轉為實際型別的指標

5new失敗時丟擲std::bad_alloc異常;malloc分配失敗時返回空指標null。

iOS全域性變數與屬性的記憶體管理

在ios開發中,為了節約時間,程式設計師經常會用全域性變數代替屬性。但是這樣做,尤其是新手開發中,經常會引起記憶體洩露的報錯,其實作為蘋果自己也沒有給出乙個完美安全的記憶體管理 例子。但是在ios開發到如今,有乙個相對比較安全的記憶體管理模版。void viewdidload void viewdi...

MATLAB記憶體變數的管理

1.為陣列賦值 利用連續的記憶體分配。但是陣列型別和維數作為陣列的頭資訊儲存在其他的地方。兩者沒有存放在同一連續的記憶體區域 2.刪除陣列中的元素 先移除陣列元素,後壓縮原來分配給陣列的記憶體空間。3.維陣列增加元素 觀察陣列所在的連續區域中是否可以增加新元素。如果可以容納新增加的陣列元素則僅需要擴...

Python變數記憶體管理

思考 當變數值命名以及生成的時候,會在 儲存著呢 x 10當我們在p1.py中定義乙個變數x 10,那麼計算機把這個變數值10存放在 呢了?我們回顧計算機的三大核心元件為 cpu 記憶體和硬碟。一定不是cpu,那是存放在記憶體還是硬碟中了呢?我們再回顧變數執行的三個過程,如果我們沒有使用python...