摘要:釋放不完全導致內存泄漏。既然把柔性數組放在動態內存管理一章,可見二者有必然的聯系。包含柔性數組的結構用進行動態內存分配,且分配的內存應大于結構大小,以滿足柔性數組的預期。使用含柔性數組的結構體,需配合以等動態內存分配函數。
當我們用類型如int
,char
創建變量時,所開辟的空間都是固定的。而開辟動態內存就是為了靈活的使用內存,以滿足程序的需要。
在語言學習時,對于內存的劃分為上述三者:棧區,堆區,靜態區。棧區存放臨時變量,靜態區存放靜態變量,堆區用來動態開辟。
動態內存開辟是在堆區上開辟空間,具體如何開辟請看下列函數。
malloc
& free
void* malloc( size_t size );
Return Valuemalloc returns a void pointer to the allocated space, or NULL if there is insufficient(不充足) memory available. To return a pointer to a type other than void, use a type cast(轉換) on the return value. Always check the return from malloc, even if the amount of memory requested is small.Parametersize - Bytes to allocate RemarksThe malloc function allocates a memory block of at least size bytes. The block may be larger than size bytes because of space required for alignment and maintenance information.
void free( void* memblock );
Return ValueNoneParametermemblock - Previously allocated memory block to be freedRemarksThe free function deallocates(解除) a memory block that was previously allocated. If memblock is NULL, the pointer is ignored. Attempting to free a memblock isn"t allocated on heap may cause errors.
malloc
函數在堆區上申請size
個字節的空間,并返回該空間的起始地址。
free
函數釋放指針指向的動態開辟的空間,但不對指針造成任何影響。
malloc
返回通用類型的指針,將其強制轉換為所需類型,并用該類型的指針維護該內存空間。NULL
。free
釋放內存以防內存泄漏,將指針置空避免成為野指針。//申請空間int* p = (int*)malloc(40);//檢查if (p == NULL) { printf("%s/n", strerror(errno)); return -1;}//使用for (int i = 0; i < 10; i++) { *(p + i) = i; printf("%d ", *(p + i));}//釋放空間free(p);//置空p = NULL;
calloc
void* calloc( size_t num, size_t size );
Return Valuecalloc returns a pointer to the allocated space. To get a pointer to a type other than void, use a type cast on the return value. Parameters1. num - Number of elements2. size - Length in bytes of each elementRemarksThe calloc function allocates storage space for an array of num elements, each of length size bytes. Each element is initialized to 0.
malloc
函數在堆區上申請num
個size
大小的空間,返回起始地址并將內容初始化為0。
int* p = (int*)calloc(10, sizeof(int));if (p == NULL) { perror(""); return -1;}for (int i = 0; i < 10; i++) { *(p + i) = i; printf("%d ", p[i]);}free(p);p = NULL;
realloc
void* realloc( void* memblock, size_t size );
Return Valuerealloc returns a void pointer to the reallocated memory block. The return value is NULL if there is not enough available memory to expand the block to the given size, then the original block is unchanged.Parameters1. memblock - Pointer to previously allocated memory block2. size - New size in bytesRemarksThe realloc function changes the size of an allocated memory block. The memblock parament points to the beginning of the memory block. If memblock is NULL, realloc behaves the same way as malloc. The contents of the block are unchanged, although the new block can be in a different location.
realloc
函數為已開辟的空間重新開辟大小。
NULL
。//1.p = (int*)realloc(p, 20 * sizeof(int));//2.int* ptr = (int*)realloc(p, 20 * sizeof(int));if (ptr == NULL) { return -1;}p = ptr;
防止增容失敗將原空間指針置空,故不可直接使用原指針接受返回值。判斷非空后再賦給原指針。
?
void test() { int* p = (int*)malloc(INT_MAX / 4); *p = 20; free(p);}
對指向動態開辟的空間的指針一定要做有效的判斷。
void test() { int i = 0; int* p = (int*)malloc(10 * sizeof(int)); if (NULL == p) { exit(EXIT_FAILURE); } for (int i = 0; i <= 10; i++) { *(p + i) = i; } free(p); p = NULL;}
作為程序員必須有意識地檢查所寫的代碼是否有越界訪問的問題。
void test() { int a = 10; int* p = &a; free(p); p = NULL;}
不可用free
釋放非動態開辟的空間。
int main(){ int* p = (int*)malloc(100); p++; free(p); return 0;}
改變指向動態開辟內存的指針,內存將無法管理。釋放不完全導致內存泄漏。
void test() { int* p = (int*)malloc(100); free(p); free(p);}
使用free
釋放已釋放的空間,即訪問非法內存。建議釋放內存和指針置空搭配使用。
void test() { int *p = (int*)malloc(100); if(NULL != p) { *p = 20; }}int main() { test(); while(1);}
使用結束不釋放內存造成內存泄漏。程序不停止,系統也不會自動回收。
?
調用下列
test
函數,解釋運行結果。
void GetMemory(char* p) { p = (char*)malloc(100);}void test() { char* str = NULL; GetMemory(str); strcpy(str, "hello world"); printf(str); free(str); str = NULL;}
程序報錯。
傳值調用:并沒有改變str
的值仍為不予修改的空指針,可以使用二級指針接收str
的地址。函數調用結束后指針銷毀故無法釋放空間以致內存泄漏。
char* GetMemory() { char p[] = "hello world"; return p;}void test() { char* str = NULL; str = GetMemory(); printf(str); free(str); str = NULL;}
程序打印隨機值。
返回棧空間地址:數組p
在函數內創建,出函數銷毀,返回這部分空間的地址 ,屬于訪問非法空間。
void GetMemory(char** p,int num) { *p = (char*)malloc(num);}void test() { char* str = NULL; GetMemory(&str, 100); strcpy(str, "hello"); printf(str); free(str); str = NULL;}
程序運行成功,打印
"hello"
。
傳址調用:本題是例一的正確寫法。
void test(void) { char* str = (char*)malloc(100); strcpy(str, "hello"); free(str); if (str != NULL) { strcpy(str, "world"); printf(str); }}
程序報錯。
野指針:動態開辟的內存釋放后指針不置空,造成野指針訪問非法內存。釋放內存和指針置空應該搭配起來使用。
釋放空間,銷毀空間都是將內存空間歸還給操作系統,即將此空間的使用權限歸還操作系統。雖不會改變空間內容以致打印出所謂的“正確結果”,但可能在之后被操作系統分配給其他程序時發生修改。但無論改變與否,一旦空間歸還后再去訪問就是訪問非法內存。
?
根據下列創建的各種變量,分析內存的劃分。
int globalVar = 1;static int staticGlobalVar = 1;int main(){ static int staticVar = 1; int localVar = 1; int num1[10] = { 1,2,3,4 }; char char2[] = "abcd"; char* pChar3 = "abcd"; int* ptr1 = (int*)malloc(4 * sizeof(int)); int* ptr2 = (int*)calloc(4, sizeof(int)); int* ptr3 = (int*)realloc(ptr2, 4 * sizeof(int)); free(ptr1); free(ptr3); return 0;}
globalVal
,staticGobalVar
,staticVar
分別是全局變量和靜態變量,在數據段上創建。localVar
和num
,char2
,pchar
以及ptr
本身都是局部變量,都是在棧區上創建的。malloc
,calloc
,realloc
都是在堆區上開辟的內存塊,由指針ptr
指向而已。stack
):執行函數時,函數的局部變量都會在棧區上創建。壓棧:從棧頂向下開辟空間,彈棧:從棧底向上釋放空間。heap
):一般由程序員分配和釋放,從堆低向上開辟空間,堆頂向下釋放空間。在程序結束后也被操作系統會自動回收。static
修飾后放在常量區,程序結束后由系統釋放。語言學習時期,僅對內存作此了解即可。內核空間和內存映射段會在操作系統中學習,此處不再深入研究。
?
C99中引入柔性數組。柔性數組(flexible array)面試中雖不是重要的考點,但仍需掌握最基本的使用。
在C99
中,結構中最后一個元素允許是未知大小的數組,被稱為柔性數組成員。例如:
//1.struct st_type { int i; int a[0];//柔性數組成員};//2.struct st_type { int i; int a[];//柔性數組成員};
語法規定數組大小中寫0和不寫都代表不指定大小。意味數組可大可小,這便是柔性的含義。
有些編譯器可能只支持一種寫法。當然柔性數組前必須有其他成員,類型一致是為了避免考慮內存對齊。既然把柔性數組放在動態內存管理一章,可見二者有必然的聯系。
結構中柔性數組成員前必須至少有一個成員。
sizeof
計算結構所占空間時不包含柔性數組的大小。
包含柔性數組的結構用malloc
進行動態內存分配,且分配的內存應大于結構大小,以滿足柔性數組的預期。
使用含柔性數組的結構體,需配合以
malloc
等動態內存分配函數。分配空間減去其他成員的大小,即為為柔性數組開辟的空間。
malloc
開辟的大小寫成如圖所示的形式,增加代碼的可閱讀性。結構體所分配空間減去其他成員的大小,所剩即為為柔性數組開辟的空間大小,若不夠還可以用
realloc
調整大小,以滿足柔性數組“柔性”的需求。
struct st_type { int i; int a[0];};int main() { printf("%d/n", sizeof(struct st_type)); //1. struct st_type st; //2. struct st_type* pst = (struct st_type*)malloc(sizeof(struct st_type) + 10 * sizeof(int)); if (pst == NULL) { perror("pst"); return -1; } return 0;}
含柔性數組結構體當然不可像第一種那樣使用,這樣結構體變量st
僅有4個字節,不包含柔性數組。
struct st_type { int i; int a[0];};int main() { struct st_type* pst = (struct st_type*)malloc(sizeof(struct st_type) + 10 * sizeof(int)); if (pst == NULL) { perror("pst"); return -1; } pst->i = 10; for (int i = 0; i < 10; i++) { printf("%d ", pst->a[i] = i); } //調整空間大小 struct st_type* ptr = (struct st_type*)realloc(pst, sizeof(struct st_type) + 20 * sizeof(int)); if (ptr == NULL) { perror("ptr"); return -1; } pst = ptr; for (int i = 10; i < 20; i++) { printf("%d ", pst->a[i] = i); } //釋放 free(pst); pst = NULL; return 0;}
柔性數組成員利用動態內存可大可小,那同樣將柔性數組成員替換成指向動態開辟內存的指針也可達到同樣的效果。下文將對比二者都有何優劣。(為突出對比,已省略不必要的代碼)
struct st_type { int i; int a[];};int main() { struct st_type* pst = (struct st_type*)malloc(sizeof(struct st_type) + 10 * sizeof(int)); for (int i = 0; i < 10; i++) { printf("%d ", pst->a[i] = i); } //調整空間大小 struct st_type* ptr = (struct st_type*)realloc(pst, sizeof(struct st_type) + 20 * sizeof(int)); pst = ptr; for (int i = 10; i < 20; i++) { printf("%d ", pst->a[i] = i); } //釋放 free(pst); pst = NULL; return 0;}
struct st_type { int i; int* pa;};int main() { struct st_type* pst = (struct st_type*)malloc(sizeof(struct st_type)); pst->pa = (int*)malloc(10 * sizeof(int)); for (int i = 0; i < 10;
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/121538.html
摘要:棧內存分配運算內置于處理器的指令集中,效率很高,但是分配的內存容量有限。棧區主要存放運行函數而分配的局部變量函數參數返回數據返回地址等。 C語言動態內存分配篇 目錄 一、為什么存在動態內存管理/分配? ????????內存的存儲形式劃分 二、動態內存函數的介紹 ????????malloc ...
摘要:在運行腳本時,需要顯示的指定對象。大對象區每一個區域都是由一組內存頁構成的。這里是唯一擁有執行權限的內存區。換句話說,是該對象被之后所能回收到內存的總和。一旦活躍對象已被移出,則在舊的半空間中剩下的任何死亡對象被丟棄。 內存管理 本文以V8為背景 對之前的文章進行重新編輯,內容做了很多的調整,使其具有邏輯更加緊湊,內容更加全面。 1. 基礎概念 1.1 生命周期 不管什么程序語言,內存...
摘要:之前的通訊錄在程序退出后內部的數據就會消失,再次打開程序后只能重新輸入數據,為此我們增加了一個保存功能來保存信息。 前言: 由于之前實現的通訊錄在存儲方面只能支持靜態的1000人的存儲量,但是如果聯系人較少,則會造成較大的內存浪費。而當聯系人一旦超過1000時,就不能再繼續存儲信息了。因...
閱讀 963·2021-11-24 10:42
閱讀 3474·2021-11-19 11:34
閱讀 2605·2021-09-29 09:35
閱讀 2525·2021-09-09 09:33
閱讀 640·2021-07-26 23:38
閱讀 2515·2019-08-30 10:48
閱讀 1385·2019-08-28 18:07
閱讀 421·2019-08-26 13:44