內存分配方式:
1.從靜態存儲區分配,內存在程序編譯的時候就已經分配好了(即已經編址),這些內存在程序的整個運行期間都存在,如全局變量,static變量等。
2.在堆棧上分配,在函數執行期間,函數內部變量(包括形參)的存儲單元都創建在堆棧上,函數結束這些存儲單元自動釋放,堆棧清退。堆棧內存分配運算內置於處理器的指令集中,效率很高,並且一般不存在失敗的危險,但是分配的內存容量有限,可能出現堆棧溢出。
3.從堆(heap)或自由存儲空間上分配,即動態內存分配,程序在運行期間,用malloc()或者new申請任意數量的內存,程序員自己掌握釋放內存的恰當時機(使用free()或delete),動態內存的生存期由程序員決定,使用靈活、
常見的內存錯誤:
1.內存尚未分配成功,卻使用了。 檢查指針是否爲空
2.內存分配成功,但是尚未初始化就使用它 任何的分配需要初始化
3.內存分配成功已經初始化,但是訪問越過了內存的邊界。 如數據的越界訪問
4.忘記釋放內存或者只是釋放了一部分的內存,導致內存泄露。 malloc() free() new delete 使用必須配對
5.釋放了內存卻還在使用。 注意將已經釋放的內存設置爲NULL,防止產生野指針。 多次釋放同一塊內存出現錯誤。 double free
幾點規則:
1.用malloc()或者new申請內存之後,應該立即檢查指針值是否爲NULL或者進行異常處理,以防止使用值爲NULL的指針。
2.不要忘記初始化指針,數組和動態內存,防止將未初始化的內存作爲右值使用。
3.避免數組下標訪問越界。
4.動態內存的分配和釋放必須配對,防止內存泄露。
5.釋放內存後應該立即把指針設置成NULL,防止野指針。
指針參數如何傳遞內存:
1.指針作爲參數進行內存的分配,傳遞指針的指針,或者傳遞指針的引用。因爲實參是拷貝一份傳遞給形參。
void getmemory(char** p,int num)
{
*p=(char*)malloc(sizeof(char)*num);
}
void getmemory(char*& p,int num)
{
p=new char;
}
2.用函數返回值傳遞來申請內存
char* getmemory(int num)
{
char* p=NULL;
p=(char*)malloc(num*sizeof(char));
return p;
}
3.注意不可以返回局部變量的地址
char* getmemory(int num)
{
char* p="hello world";
return p;
}
char* getmemory()
{
char p[]="hello world";
return p;
}
第一種 返回常量存儲區的地址OK 第二種錯誤!!
內存釋放:
#include <iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
int main()
{
int* p=new int(5);
if(p==NULL) throw 1;
cout<<p<<endl;
delete p;
cout<<p<<endl;
return 0;
}
指針被釋放後其指向的地址內人不變,(不等於NULL),但是該地址對應的內存是垃圾------>p成了一個野指針。 所以必須進行設置成NULL
經典:指針消亡了,並不代表它所指的內存會被自動釋放 AND 內存被釋放了,並不表示指針會消亡或者成了NULL。
野指針:
1.未初始化指針變量,任何指針在初始化時不會自動成爲NULL指針,它會亂指一氣,所以指針變量創建的同時應該初始化,或者設置成NULL。
2,.指針p被釋放後,未設置爲NULL。
3.指針變量超越了變量的作用範圍。
class A{
public:
void func(void){cout<<"A::func"<<endl;}
~A(){cout<<"~A()"<<endl;}
};
int main()
{
A* p=NULL;
{
A a;
p=&a;//注意a的生命期
}
p->func();//p是野指針
return 0;
}
上述代碼: 根本原因是a雖然退棧,但是僅僅是調用了析構函數,並沒有清除a的內存(a的內存仍然在函數堆棧上),所以結果沒有錯。
MALLOC FREE AND NEW DELETE
maloc,free爲C語言的庫函數,而不是運算符。 new delete是運算符而不是庫函數
用malloc,free函數進行對象的動態內存管理,不能調用構造函數和析構函數。必須程序員自己寫函數來完成初始化和清除的工作。
new.delete會自動的調用構造和析構函數來進行調用。
某些情況下,malloc/free效率更高。用戶可以自定義類重載 new/delete實現個性的內存分配和釋放策略。
注意:如果使用free()來釋放new創建的對象,那麼該對象可能會無法執行析構函數而導致程序出錯, C++並不保證new的底層會用malloc(),而且在一些實現中,malloc和new使用不同的堆,同樣,用delete釋放malloc申請的動態內存,理論是程序不會出錯,但是該程序的可讀性會很差。
p==NULL free多次都沒事,但是p!=NULL,多次釋放會出現錯誤