1.棧、堆和靜態區
靜態區:儲存自動全域性變數和static變數(包括全域性靜態變數和區域性靜態變數)。靜態區的內容在整個程式的生命週期內都存在。
棧:儲存區域性變數。棧上的內容只在函式的範圍內存在,當函式執行結束,這些內容也會自動被銷毀。其特點是效率高,但是空間大小有限。
堆:由malloc系列函式或new操作符分配的記憶體。其生命週期由free或delete決定。在沒有釋放之前一直存在,直到程式結束。其特點是使用靈活,空間比較大,但容易出錯。
2.常見的記憶體錯誤以及對策
2.1指標沒有指向一塊合法的記憶體
定義了指標變數,但是沒有為指標分配記憶體,即指標沒有指向一塊合法的記憶體。
2.1.1結構體成員指標未初始化
struct studentstu,*pstu;
int main(void)
定義了結構體變數stu,但是它沒有想到這個結構體內部char * name這個成員在定義結構體變數stu時,只是給name這個指標變數本身分配了4個位元組。name指標並沒有指向乙個合法的位址,這時候其內部存的只是一些亂碼。所在在呼叫strcpy函式時,會出現段錯誤。
解決辦法是需要name分配空間。
struct studentstu,*pstu;
int main(void)
上面也是只給pstu分配了空間,而沒有給name分配空間,同樣會出現錯誤。
正確的例項:
struct studentstu,*pstu;
int main(void)
2.1.2 沒有為結構體指標分配足夠的記憶體
struct studentstu,*pstu;
int main(void)
為pstu分配記憶體的時候,分配的記憶體大小不合適。這裡把sizeof(struct student)誤寫為sizeof(struct student *),當然name也沒有被分配空間,拷貝的時候肯定會出錯。
2.1.3 函式的入口校驗
不管什麼時候,我們使用指標之前一定要確保指標是有效的。
2.2 為指標分配的記憶體太小
為指標分配了記憶體,但是記憶體大小不夠,代指出現越界錯誤。
char *p1 = "abcdgeg";
char *p2 = (char *)malloc(sizeof(char)*strlen(p1));
strcpy(p2,p1);
p1是字串常量,其長度是7個字元,但其所佔記憶體大小為8個byte。字串常量的結束標誌是'\0'。這樣的話,將導致p1字串常量最後乙個空字元沒有被拷貝到p2中,解決的辦法是加上這個字串結束標誌符。char *p2 = (char *)malloc(sizeof(char)*strlen(p1) + 1*sizeof(char));
注意:只有字串常量才有結束標誌符。
2.3 記憶體分配成功,但並未初始化
int i=10;
char *p = (char*)malloc(sizeof(char));
在我們還不確定這個變數的初值時,可以將其初始化為0或者null。
int i=0;
char *p = null;
定義了陣列的話,可以這樣初始化:
int a[10] = ;
或者使用memset函式,memset(a,0,sizeof(a));
如果指標變數未被初始化,會導致if語句或者assert語句校驗失敗。
2.4 記憶體越界
記憶體分配成功,且已經初始化,但是操縱越過了記憶體的邊界。
2.5記憶體洩露
記憶體洩露是很難避免的。會產生洩露的記憶體就是堆上的記憶體,也就是由malloc系列函式分配的記憶體。如果用完沒有及時free或
delete,這塊記憶體就無法釋放,知道整個程式終止。
2.5.1如果使用malloc
(void *)malloc(int size);
malloc函式的返回值是乙個void型別的指標,引數為int型別資料,即申請分配的記憶體大小,單位是byte。記憶體分配成功之後,
malloc函式返回這塊記憶體的首位址。你需要乙個指標來接收這個位址。但是由於malloc返回值是void*型別的,所以必須強制轉換成
你所接收的型別。也就是說這塊記憶體將要用來儲存什麼型別的資料。
分配完成之後需要檢驗是否分配成功。
if(null != p)
2.5.2 記憶體釋放
free(p);
free函式就做了一件事:斬斷指標變數與這塊記憶體的關係。
我們可以說malloc函式分配的記憶體塊是屬於p的,因為我們對這塊記憶體的訪問都需要通過p來進行。free函式就是把這塊內
存和p之間的所有關係斬斷。從此p和哪塊記憶體之間的所有關係斬斷。至於指標變數p本身儲存的位址並沒有改變,但是它對這個位址
處的哪塊記憶體卻已經沒有所有權了。那塊被釋放的記憶體裡面儲存的值也沒有改變,只是再也沒有辦法使用了。
malloc與free配對使用,不然肯定出錯。
2.5.3記憶體釋放之後
既然free函式之後指標變數p本身儲存的位址並沒有改變,哪我們就需要重新把p的值變為null;
釋放完了指標,一定要設定指標為null。
2.5.4 記憶體已經被釋放了,但是繼續通過指標來使用
一般有三種情況:
1.就是free(p)之後,繼續通過p指標來訪問記憶體。解決辦法就是給p設定為null。
2.函式返回棧記憶體。比如在函式內部定義了乙個陣列,卻用return語句返回指向該陣列的指標。
3.記憶體使用太複雜,弄不清哪塊記憶體被釋放了,哪塊記憶體沒有被釋放。解決的辦法是重新設計程式,改善物件之間的呼叫關係。
object c 記憶體管理學習筆記
nsautoreleasepool pool nsautoreleasepool alloc init pool drain 這個函式可以把autoreleasepool裡的物件釋放 在for迴圈中每次都釋放記憶體池的示例 nsautoreleasepool temppool for i 0 i a...
effectiveC 記憶體管理 學習筆記
1.盡量使用初始化列表而不要再建構函式裡賦值,初始化順序和宣告的順序一致,一些型別如const,引用等,必須使用初始化。對於非內部資料型別成員物件應當採用初始化表,以獲取更高的效率。example b b const a a m a a 只呼叫了類a的拷貝建構函式 2.基類都使用虛析構函式,這樣才能...
記憶體管理學習筆記1
背景 乙個人想要遛狗,中途可以換別的狗遛 所以首先得有乙個狗的類 dog 然後乙個 person類 裡有乙個dog的變數,自己過載setdog函式 synthsize dog dog void setdog dog adog if dog adog 先判斷要設定的狗是不是原來的狗,避免誤設定同一條狗...