c語言--記憶體學習總結
變數在記憶體中的形式
1.定義
作用域 :變數聲明後時,只有在一定區域內才能被訪問
儲存期:程式中變數的儲存終止時間
連結: 連結屬性是為了說明在不同檔案中出現的相同識別符號應該如何處理
- 作用域(分類)
- 塊作用域
- 函式作用域
- 檔案作用域
ps:作用域只與變數定義的位置有關,在哪裡定義,作用域就是哪裡!
2.關鍵字
- auto(void):自動(作用域結束,儲存期結束,無連結)
- register:暫存器(不在記憶體中儲存,無法獲取地址,但響應快)
- extern:外部變數
- static:
- 靜態變數(程式結束,儲存期結束)
- 隱藏(表1)
- 預設初始化為0
ps1: 關鍵字不會影響作用域,只是對儲存期和連結的修改
ps2: register---系統根據實際情況,選擇是否將變數放入暫存器中
ps3: extern---在檔案中使用外部連結變數,要extern宣告,否則會被隱藏
ps4: extern---它的作用是表示變數或者函式的定義在別的檔案中,而不是建立外部變數
ps5: static---不用擔心自己定義的變數,是否會與其它檔案中的同名
ps6: 當重名出現時,內層會掩蓋外層變數,但不會覆蓋(只是另外建立一個新的同名變數)
作用域 | 效果 |
---|---|
檔案 | 內部連結,其他檔案無法呼叫 |
主函式 | 內部連結,與系統自動設定相同 |
自定義函式 | 無連結,主要目的是靜態變數 |
3.儲存型別
儲存類別 | 儲存期 | 作用域 | 連結 |
---|---|---|---|
自動 | 自動 | 塊 | 無 |
暫存器 | 自動 | 塊 | 無 |
靜態外部連結 | 靜態 | 檔案 | 外部 |
靜態外部連結 | 靜態 | 檔案 | 內部 |
靜態無連結 | 靜態 | 塊 | 無 |
分配記憶體
1.malloc()和free()
if(scanf("%d",&max)!=1)
{
puts("Number not correctly entered---bye.");
exit(EXIT_FAILURE);
}
double* ptd;
ptd=(double *)malloc(max*sizeof(double));
long* new;
new=(long *)calloc(max,sizeof(long));
if(ptd == NULL)
{
puts("Memory allocation failed.Goodbye.");
exit(EXIT_FAILURE);//程式意外退出
}
free(ptd);
free(new);
ps1: malloc() free() exit()都在stdlib.h的標頭檔案中
ps2: malloc()返回值是指標,成功為首地址,失敗為空指標
ps3: free()能清除malloc()或calloc()分配的記憶體
ps4: malloc()生成的陣列,依然可以進行陣列操作
ps5: 使用malloc()後,記得用free()釋放動態記憶體,防止記憶體洩漏
ps6: 一般exit(EXIT_SUCCESS)表示程式壽終正寢,exit(EXIT_FAILURE)表示死於非命。
ps7: 同一塊記憶體多次使用,對於需要短暫使用記憶體的部分很使用
ps8: 使用malloc時,有可能無法成功分配記憶體,一定要判斷地址是否為空指標malloc函式的實質體現在,它有一個將可用的記憶體塊連線為一個長長的列表的所謂空閒連結串列。呼叫malloc函式時,它沿連線表尋找一個大到足以滿足使用者請求所需要的記憶體塊。然後,將該記憶體塊一分為二(一塊的大小與使用者請求的大小相等,另一塊的大小就是剩下的位元組)。接下來,將分配給使用者的那塊記憶體傳給使用者,並將剩下的那塊(如果有的話)返回到連線表上。呼叫free函式時,它將使用者釋放的記憶體塊連線到空閒鏈上。到最後,空閒鏈會被切成很多的小記憶體片段,如果這時使用者申請一個大的記憶體片段,那麼空閒鏈上可能沒有可以滿足使用者要求的片段了。於是,malloc函式請求延時,並開始在空閒鏈上翻箱倒櫃地檢查各記憶體片段,對它們進行整理,將相鄰的小空閒塊合併成較大的記憶體塊。如果無法獲得符合要求的記憶體塊,malloc函式會返回NULL指標,因此在呼叫malloc動態申請記憶體塊時,一定要進行返回值的判斷。
2.儲存類別與記憶體分配
儲存類別 | 記憶體分配 |
---|---|
靜態儲存 | 程式宣告建立,程式結束消失 |
自動儲存 | 儲存在棧中,按順序加入相反順序銷燬 |
動態分配 | 儲存不連續, 使用相對較慢 |
3.程式執行期間的幾種記憶體
1、棧區:由編譯器自動分配 存放函式的引數值,區域性變數的值等,操作方式類似於資料結構中的棧。
2、堆區:一般由程式設計師分配釋放,若程式設計師不釋放,程式結束時 可能 有系統收回。它與資料結構中的堆是兩回事。分配方式類似於連結串列。
3、全域性區(靜態區):全域性變數和靜態變數是儲存放在一塊的,初始化的全域性變數和靜態變數在一個區域,未初始化的在相鄰的另一個區域。
程式結束後由系統釋放。
4、文字常量區:常量字串就存放在這裡。程式結束後有系統自動釋放。
5、程式程式碼區:存放函式體的二進位制程式碼。
4.函式名與記憶體
- 程式中的函式名、變數名、標號都是一個代號,對應一個地址,就如同指標一樣。編譯程式在程式中發現你使用函式名時,就會相應替換使用函式名的地方用這個地址*
- 編譯後在彙編裡面呼叫的就是純粹記憶體地址了之間的呼叫和我們定義的變數名函式名就沒關係了
- 原始碼編譯後,函式本身成為一個以入口地址開始的連續內容(操作資料段的程式碼、只有程式碼,沒有資料),函式名將被徹底抹掉。不過有時候你寫dll會發現函式名仍然以某種形式保留下來,但是那些名字只是為了提供給程式載入器識別用的。到了執行狀態凡是用到的函式,對應的名稱都會被替換成程式碼地址。