1. 程式人生 > >基礎知識之記憶體管理基礎

基礎知識之記憶體管理基礎

記憶體分配方式有三種:
(1) 從靜態儲存區域分配。記憶體在程式編譯的時候就已經分配好,這塊記憶體在程式的整個執行期間都存在。例如全域性變數,static 變數。
(2) 在棧上建立。在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函式執行結束時這些儲存單元自動被釋放。棧記憶體分配運算內置於處理器的指令集中,效率很高,但是分配的記憶體容量有限。
(3) 從堆上分配,亦稱動態記憶體分配。程式在執行的時候用 malloc 或 new 申請任意多少的記憶體,程式設計師自己負責在何時用 free 或 delete 釋放記憶體。動態記憶體的生存期由我們決定,使用非常靈活,但問題也最多。
【規則 7-2-1】用 malloc 或 new 申請記憶體之後,應該立即檢查指標值是否為 NULL。
防止使用指標值為 NULL 的記憶體。
【規則 7-2-2】不要忘記為陣列和動態記憶體賦初值。防止將未被初始化的記憶體作為右
值使用。
【規則 7-2-3】避免陣列或指標的下標越界,特別要當心發生“多 1”或者“少 1”
操作。
【規則 7-2-4】動態記憶體的申請與釋放必須配對,防止記憶體洩漏。
【規則 7-2-5】用 free 或 delete 釋放了記憶體之後,立即將指標設定為 NULL,防止產生野指標。

char a[]="hello";
a[0] = 'x';
cout<<a <<endl;
char *p = "world";//注意p指向常量字串,位於靜態儲存去,不能被修改
p[0] = 'x';//執行錯誤
cout<<p<<endl;

計算記憶體容量:

char a[]="hello world";
char *p = a;
cout<<sizeof(a)<<endl;//12位元組
cout<<sizeof(p)<<endl;//4位元組
void func(char a[100])
{
cout
<<sizeof(a)<<endl; }

指標引數是如何傳遞記憶體的?
如果函式的引數是一個指標,不要指望用該指標去申請動態記憶體。如下的例子中,GetMemory並沒有使得str獲得期望的記憶體,str依舊是null

void GetMemory(cha *p,int num)
{
p = (char*)malloc(sizeof(char)*num);
}
void Test(void)
{
char *str = NULL;
GetMemory(str,100);
strcpy(str,"hello");
}

為了處理這種情況,非得要用指標引數去申請記憶體,那麼應該改用“指向指標的指標”

void GetMemory2(char **p, int num)
{
*p = (char *)malloc(sizeof(char) * num);
}
void Test2(void)
{
char *str = NULL;
GetMemory2(&str, 100);
// 注意引數是 &str,而不是 str
strcpy(str, "hello");
cout<< str << endl;
free(str);
}

free和delete:只是把指標所值的 記憶體給釋放掉,但i並沒有把指標本身幹掉。
用的。
野指標:是指向垃圾記憶體的指標。主要成因有:

  1. 指標變數沒有被初始化。任何指標變數在剛被建立時不會自動成為NULL指標,它的預設值是隨機的,,會亂指一氣。所以,指標變數在建立的同時應當被初始化,要麼設定為NULL,要麼讓指向合法的記憶體。
  2. new和delete:
    new內建了sizeof、型別轉換和型別安全檢查功能。對於非內部資料型別
    的物件而言,new 在建立動態物件的同時完成了初始化工作。
    如果用new建立物件陣列,那麼只能使用物件的無引數建構函式。
    Obj *objects = new Obj[100]; // 建立 100 個動態物件
    Obj *objects = new Obj[100](1);// 建立 100 個動態物件的同時賦初值 1,錯誤的。
    delete釋放物件陣列時:
    delete []objects; // 正確的用法
    delete objects; // 錯誤的用法,後者相當於 delete objects[0],漏掉了另外 99 個物件。