標籤:style blog color 使用 ar for 資料 div log
1.
靜態記憶體
編譯的時候預申請的記憶體,不需要自己管理,所屬函數執行完畢後自動回收
缺陷:
類似下面的函數會出錯:
char *uppr(char *oldstring){ char newstring[100]; ... return newstring;}
因為函數執行完畢後字元數組new已經被銷毀了,指標指向的位置當然就不是正確的地址。
此函數可以通過以下方式解決:
void uppr(char *old,char *new){ ...}
可以將兩個字元數組傳入,然後將更改寫回new中。
可以實現的原因是new 所代表的數組地址是主函數定義的,更改不會隨著子函數銷毀而銷毀,因此在子函數中對主函數變數指標的改變可以實現,經典實現就是雙返回的交換
如下:
void swap(int *a,int *b){ int c; c=*a; *a=*b; *b=c;}調用swap(&a,&b);
2.
溢出
使用了超出已申請的記憶體,就是在申請數組是100個元素的情況下寫入了101及以上個元素,或企圖讀取到101個及以上位置的元素
引用錯誤的結果不可預期,通常安全性都出自溢出區,讀取了本來不能讀取的位置而啟動了另外的程式。
寫入的錯誤可能會導致其他程式的資料被覆蓋,程式也會出現錯誤。
解決方式:
通常是在進行操作時判斷空間大小,進行截取,即將超出部分刪除,但是這樣會導致資料丟失
3.
動態記憶體
在程式運行過程中動態進行分配的記憶體,通常是自己申請
主要函數
#include<stdlib.h>void *malloc(size_t size)void *calloc(size_t nmemb,size_t size)
釋放記憶體void *free(void *ptr)
調整記憶體void *realloc(void *ptr,size_t size)
注意動態記憶體的釋放不由系統決定,而是必須使用free函數才能釋放,因此在子函數中可以返回指向申請的記憶體的指標
例如:
char *uppr(char *old){ char *new; if(new=malloc(strlen(old)+1)){ strcpy(new,old); int i; for(i=0;i<strlen(new);++i){ if(new[i]>=97 && new[i]<=122){ new[i]-=32; } } }else{ exit(255); } return new;}
此時子函數執行完畢後new並不會被銷毀,因此可以返回此地址,但是在使用完畢後最好將他是free掉。
另外,realloc函數當ptr為NULL時,等價於malloc,size為0時,相當於free
注意free後指標變為懸null 指標,不可以訪問(不是不能,訪問懸null 指標會發生不可預知的異常)。
4.
分配堆棧
#include<stdlib.h>void *alloca(size_t size)
此時分配的記憶體在函數結束時被自動收回,一般很少用
5.
記憶體鎖定
一般情況下,如果記憶體一段時間內不使用,系統會自動將其轉移到磁碟上原位置放置新資料,如果想禁止此地區被轉移,可以使用記憶體鎖定
常用函數為
#include<sys/types.h>
//鎖定記憶體首地址+長度int mlock(const void *addr,size_t length);
//解鎖記憶體,首地址+長度int munlock(void *addr,size_t lemgth);
/*鎖定記憶體頁,flag選項:
*MCL_CURRENT 所有記憶體頁
*MCL_FUTURE 所有為進程添加的地址頁
*/
int mlockall(int flag);int munlockall(void);
(以上函數只限root使用者)
記憶體管理-Linux下C編程指南