1. 程式人生 > >關於C語言的malloc函式以及記憶體洩漏的問題

關於C語言的malloc函式以及記憶體洩漏的問題

malloc函式

malloc函式的原型:

(void *)malloc(int size)

 malloc函式的返回值是一個void型別的指標,引數為int型別的資料,即申請分配的記憶體大小,單位是位元組。記憶體分配成功之後,malloc函式返回這塊記憶體的首地址,你需要一個指標來接受這個地址。但是由於函式的返回值是void *型別,所以必須強制轉換成你所接收的型別。也就是說這塊記憶體將來要用來儲存什麼型別的資料,比如

char *p = (char *)malloc(100);

在堆上分配了100個位元組的記憶體,返回這塊記憶體的首地址,把地址強制轉換成char *型別後,賦給char *型別的指標變數p;同時告訴我們這塊記憶體將用來儲存char型別的資料。也就是說你只能通過指標變數p來操作這塊記憶體。這塊記憶體本身沒有名字,對它的訪問是匿名訪問

使用malloc函式同樣要注意這點:如果所申請的記憶體塊大於目前堆上剩餘的記憶體塊(整塊),則記憶體分配就會失敗,函式函式NULL。注意這裡說的是“堆上剩餘記憶體塊”不是所有剩餘記憶體塊之和,因為malloc函式申請的是連續的一塊記憶體。既然malloc函式申請記憶體又不成功的可能,那我們在使用指向這塊記憶體的指標時,必須用if( NULL != p)語句上來驗證記憶體分配確實成功了。

記憶體洩漏

在C語言程式設計中,記憶體洩漏幾乎是很難避免的,C程式產生洩漏記憶體,則執行速度會逐漸變慢,並最終停止執行;如果產生覆蓋記憶體,程式會變得非常脆弱,很容易受到惡意使用者的攻擊。記憶體洩漏是一種隱性危害,它們很難被發現,通常不能在相應的原始碼中找到錯誤,需要仔細分析與專門的檢測工具才能發現。

(1)記憶體洩漏的定義

通常我們所說的記憶體洩漏,是指分配出去的記憶體在使用之後沒有釋放掉,沒有回收,長此以往,會造成沒有足夠的記憶體可以分配。一般表現為執行時間越長,佔用的記憶體越多,最終導致系統奔潰。一般的記憶體洩漏是指堆記憶體的洩漏。堆記憶體是指程式從堆中分配的,大小任意的(記憶體塊的大小可以在程式執行期決定),使用完後必須顯式釋放的記憶體。應用程式一般使用malloc,realloc,new等函式從堆中分配到一塊記憶體,使用完後,程式必須負責相應的呼叫free或delete釋放該記憶體塊,否則,這塊記憶體就不能被再次使用,我們就說這塊記憶體洩漏了。

(2)記憶體洩漏的原因

2.1 C語言記憶體分配情況

 
  在C語言中,根據資料在記憶體中存在的時間(生存週期)不同,將記憶體空間分為三個區:

1)程式區:用於儲存程式的程式碼,即程式的二進位制程式碼。

2)靜態儲存區:用於儲存全域性變數和靜態變數,這些變數的空間在程式編譯時就已經分配好了。

3)動態儲存區:用於在程式執行時分配的記憶體,又分為:堆區(heap)和棧區(stack)。堆區:用於動態記憶體分配,程式執行時由記憶體分配函式在堆上分配記憶體。在C語言中,只能使用指標才能動態的分配記憶體。棧區:在函式執行時,函式內部的區域性變數和函式引數的儲存單元的記憶體區域,函式執行結束時,這些記憶體區域會自動釋放。 
  2.2 C語言動態記憶體分配 
  在C語言中用記憶體分配函式來實現記憶體的動態分配,這些函式有:malloc()和realloc()等函式。malloc():使用這個函式時需要包含標頭檔案。使用該函式需要指定要分配的記憶體位元組數作為引數,例如: 
  int *pNumber=(int *) malloc(100) 
  這條語句分配了100個位元組的記憶體,並把這個記憶體塊的地址賦給pNumber,這個記憶體塊可以儲存最大25個int值,每個int佔4個位元組。如果不能分配請求的記憶體,malloc()會返回一個null指標。 
  2.3 釋放動態分配的記憶體 
  堆上分配的記憶體會在整個應用程式結束之後,由作業系統負責回收,但最好是在使用完這些記憶體後立即釋放。如果不釋放,會引起記憶體洩漏,極大佔用系統資源,可能會產生各種未知的錯誤。所以,必須使用free()函式釋放記憶體,引數是記憶體地址(指標),例如:free(pNumber),依上例。 

(3)記憶體洩漏避免的方法 

3.1正確使用malloc函式分配記憶體 
  malloc是一個函式,專門用來從堆上分配記憶體。使用malloc函式需要幾個要求:記憶體分配給誰?分配多大記憶體?是否還有足夠記憶體分配? 記憶體將用來儲存什麼格式的資料?分配好的記憶體在哪裡? 如果這5點都確定,那記憶體就能分配。下面看看malloc的原型:(void *)malloc(int size) 
  malloc函式的返回值是一個void型別的指標,引數為int型別的資料,即申請分配的記憶體大小,單位是位元組。記憶體分配成功之後,malloc函式返回這塊記憶體的首地址,你需要一個指標來接受這個地址。也就是說這塊記憶體將來要用來儲存什麼型別的資料,如: 
  char *p = (char *)malloc(100) 
  在堆記憶體分配了100個位元組的記憶體,返回這塊記憶體的首地址,把地址強制轉換成char *型別後賦給char *型別的指標變數p;同時告訴我們這塊記憶體將用來儲存char型別的資料。你只能通過指標變數p來操作這塊記憶體,這塊記憶體本身沒有名字,對它的訪問是匿名訪問。但是,不一定每次malloc函式都能成功分配到記憶體。既然malloc函式申請記憶體存在不成功的可能,那我們在使用指向這塊記憶體的指標時,必須用if( NULL != p)語句上來驗證記憶體分配確實成功了。 


 3.2 正確使用free函式釋放記憶體 
  既然有分配,那就必須有釋放,不然的話,有限的記憶體就會用光,而沒有釋放的記憶體卻佔用空間,與malloc對應的就是free函數了。free函式只有一個引數,就是所要釋放的記憶體塊的首地址(指標)。按上例,則為:free(p).free函式其實它就做了一件事:斬斷指標變數和這塊記憶體的對應關係。free函式就是把這塊記憶體和p之間的關係斬斷;p本身的值並沒有改變或者消失,即指標變數p本身儲存的地址並沒有改變,那塊被釋放的記憶體裡面儲存的值也沒有改變。這就是free函式的功能,一個malloc對應一個free,是一夫一妻制。在使用free(p)函式記憶體釋放後,指標變數p本身儲存的地址並沒有改變,那我們必須需重新把p的值變為NULL:p = NULL。如果沒有把該指標置NULL,這個指標就成為了“懸空指標”,這是很危險的,且也是經常出錯的地方。 

相關推薦

關於C語言malloc函式以及記憶體洩漏的問題

malloc函式 malloc函式的原型: (void *)malloc(int size)  malloc函式的返回值是一個void型別的指標,引數為int型別的資料,即申請分配的記憶體大小,單位是

C語言malloc()函式與calloc()函式的區別

推薦部落格: 推薦部落格:https://blog.csdn.net/ddcodingya/article/details/80452397   推薦部落格:https:https://blog.csdn.net/Hackbuteer1/article/d

詳解C語言printf函式以及%佔位符知識

功能: C語言中產生格式化輸出的函式(定義在stdio.h系統標頭檔案中),向終端輸出 (顯示屏等。。。); 定義: int printf(const char *format,[argument

模擬實現c語言中的動態記憶體分配malloc函式

動態儲存器分配器維護著一個程序的虛擬的儲存器區域,稱為堆(heap)。分配器將堆視為一組不同大小的塊的集合來維護。每個塊就是一個連續的虛擬儲存器片(chunk),要麼是已經分配的,要麼是空閒的。 我們這裡把記憶體堆空間模擬為一個位元組陣列buf[1000],塊的資料結構為:

C語言—理解函式指標以及它的用法

什麼是函式指標? 指標前面已經寫過好多,自以為認識的差不多了,但是今天突然看到一個問題,寫一個函式指針,函式指標就是一個指向函式首地 址的指標,接下來寫幾個指標: 寫一個函式指標 寫一個函

C語言之程式在記憶體中的分佈以及記憶體越界問題

C語言程式在記憶體中的分佈: bss段:該段用來存放沒有被初始化或者初始化為0的全域性變數,以及被static修飾的未初始化的區域性變數。在程式執行的整個生命週期內都存在於記憶體中。這個段中的變數只佔用程式執行時的記憶體空間,而不佔用程式檔案的儲存空間。   舉個例子

C語言 trim函式實現

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> //去除尾部空格 char *rtrim(char *str) { if(str == N

C語言函式宣告、形參、實參

函式原型: 原型prototype是函式的宣告;描述了函式的返回值與引數;  函式原型說明了兩點: 1、該函式的返回值 2、該函式的引數及其型別 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 函式的引數: 引數到底是什

C/C++開發】C++ 解構函式以及 delete 和delete[]的整理

轉自:http://hi.baidu.com/bystander1983/item/bf0b5c12b077cfec9913d651 delete和delete[] 的區別: C++告訴我們在回收用 new 分配的單個物件的記憶體空間的時候用 delete,回收用 new[] 分配的一組物

c語言獲得動態分配記憶體後的陣列記憶體大小

c語言獲得動態分配記憶體後的陣列記憶體大小 用一個函式 :_msize(); ★注意:該函式為Windows獨有★ int* s = (int*)malloc(sizeof(int));     int i;     for(i

C語言isalpha函式

看程式碼: #include<ctype.h> #include<stdio.h> #include <iostream> using namespace std; int main(void){ char ch; int tot

c 語言函式遞迴來實現求 k 的 n 次方

       如果求取k的n次方,既可以用普通的方法實現,也可以用函式的遞迴來實現。        函式的遞迴即是自己呼叫自己的函式應用形式,即在main函式下定義一個函式,然後在這個函式內自己為了實現某個目的,函式

C語言探究函式遞迴的巧妙之處(以斐波那契數列為例)

對於許多C語言的初學者來說,函式是一個比較重要的版塊.函式的使用不僅在學習程式設計的時期可以方便我們解決一些問題.它在未來的工作中也是程式設計師們經常運用的東西.而函式的遞迴是函式這一版塊比較難懂的東西.因此小編以輸出斐波那契數列的第N項為例,來探討函式的遞迴的應用給我們的程式碼帶來的方便.

C語言高階篇 - 5.記憶體

1、馮諾依曼結構和哈佛結構      (1)馮諾依曼結構是:資料和程式碼放在一起。      (2)哈佛結構是:資料和程式碼分開存在。      (3)什麼是程式碼:函式   &nbs

C語言 strrev函式

標頭檔案:#include<string.h> strrev()函式將字串逆置,其原型為: char *strrev(char *str); 【引數說明】str為要逆置的字串。 strrev()將str所指的字串逆置。 【返回值】返回指向逆置後的字串的指標。 strr

C語言函式(侵刪)

1.strlen 標頭檔案:#include <string.h> strlen()函式用來計算字串的長度,其原型為:unsigned int strlen (char *s);  s為指定的字串 #include<stdio.h> #include<

C語言assert函式完全攻略

斷言assert函式,C語言assert函式完全攻略 對於斷言,相信大家都不陌生,大多數程式語言也都有斷言這一特性。簡單地講,斷言就是對某種假設條件進行檢查。在 C 語言中,斷言被定義為巨集的形式(assert(expression)),而不是函式,其原型定義在<assert.h>檔

C語言read函式的那些坑

  今天在複習UNIX檔案系統,用到那個read函式,但是無意中卻掉到一個坑裡了,用了一個多小時才找到問題根源,這裡記錄一下。   問題是這樣的:我需要使用read和write函式把鍵盤輸入的資訊複製到輸出。所以我寫了如下程式: #include<stdio.h> #define MAX

連結串列的C語言實現 含動態記憶體分配

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

linux下的c語言系統函式呼叫

目錄 4.linux下的系統函式的使用 c語言 4.1數學函式的使用 1pow函式 2.exp函式 3.log函式 4.rand()隨機數函式 4.2字元函式的使用 4.3系統時間與日期函式的使用 系統時間 時間間隔 4.4環境控制函式 &nb