C語言(動態記憶體分配)

鋸齒流沙發表於2017-12-27

C語言記憶體分配:

靜態記憶體:也就是棧空間記憶體,不用程式設計師自己分配。

1、棧區(stack):編譯器在需要的時候分配,在不需要的時候自動清除的變數的儲存區。棧裡面的變數通常是區域性變數、函式引數等。windows下,棧記憶體分配2M(確定的常數),超出了限制,提示stack overflow錯誤。自動分配,釋放。

動態記憶體分配:由 malloc 等分配的記憶體塊,和堆是十分相似的,不過它是用 free 來結束自己的生命的。

2、堆區(heap):由 new 分配的記憶體塊,他們的釋放編譯器不去管,由我們的應用程式去控制,一般一個 new 就要對應一個 delete。如果程式設計師沒有釋放掉,那麼在程式結束後,作業系統會自動回收。堆可以動態地擴充套件和收縮。 程式設計師手動分配釋放,作業系統80%記憶體。

3、全域性區或靜態區。

4、字元常量區。

5、程式程式碼區。

void main(){
	//靜態記憶體分配,在棧記憶體中
	int a[100*1024*1024];
	getchar();
}
複製程式碼

執行結果.png

會出現stack overflow錯誤,也就是棧溢位。

void main(){
	//動態記憶體分配
	int* p = malloc(1024*1024*sizeof(int));
	//printf("%#x\n",p);
	//釋放
	free(p);
	getchar();
}

複製程式碼

上面就是使用malloc動態分配sizeof(int)M記憶體,然後使用free釋放分配的記憶體。

靜態記憶體分配:分配固定大小的記憶體空間。 存在問題:1、容易超出棧記憶體最大值,也就是造成棧溢位。 2、為了防止記憶體不夠用會開闢更多的空間,容易浪費記憶體。

動態記憶體分配:在程式執行過程中,動態指定需要使用的記憶體大小,手動釋放,釋放之後這些記憶體還可以被重新使用。

建立一個陣列,動態指定陣列的大小

void main(){
	int size;
	scanf("%d",&size);
	
	//開闢記憶體,大小size*sizeof(int)位元組
	int* p = malloc(size*sizeof(int));
	//p是陣列的首地址,p就是陣列的名稱
	//給陣列元素賦值(使用這一塊剛剛開闢出來的記憶體區域)
	int i = 0;
	for (; i < size; i++){
		p[i] = rand() % 300;
		printf("%d     %#x\n", p[i], &p[i]);
	}
	//釋放p
	free(p);

	getchar();
}
複製程式碼

realloc :重新分配記憶體

void main(){
	int size;
	scanf("%d",&size);
	
	//開闢記憶體,大小size*sizeof(int)位元組
	int* p = malloc(size*sizeof(int));
	//p是陣列的首地址,p就是陣列的名稱
	//給陣列元素賦值(使用這一塊剛剛開闢出來的記憶體區域)
	int i = 0;
	for (; i < size; i++){
		p[i] = rand() % 300;
		printf("%d     %#x\n", p[i], &p[i]);
	}

	int addSize;
	printf("輸入陣列增加的長度:");
	scanf("%d", &addSize);
	//記憶體不夠用,擴大剛剛分配的記憶體空間
	int* p2 = realloc(p, (addSize + size)*sizeof(int));
	if (p2 == NULL){
		printf("重新分配失敗");
	}

	//重新賦值
	int j = 0;
	printf("\n\n");
	for (; j < (size + addSize); j++){
		p2[j] = rand() % 100;
		printf("%d   %#x\n", p2[j], &p2[j]);
	}
	//手動釋放記憶體
	if (p != NULL){
		free(p);
		p = NULL;
	}
	if (p2 != NULL){
		free(p2);
		p2 = NULL;
	}
	getchar();
}
複製程式碼

執行結果.png

重新分配記憶體的兩種情況: 1、縮小,縮小的那一部分資料會丟失 2、擴大,(連續的) (1)如果當前記憶體段後面有需要的記憶體空間,直接擴充套件這段記憶體空間,realloc返回原指標; (2)如果當前記憶體段後面的空閒位元組不夠,那麼就使用堆中的第一個能夠滿足這一要求的記憶體塊,將目前的資料複製到新的位置,並將原來的資料庫釋放掉,返回新的記憶體地址; (3)如果申請失敗,返回NULL,原來的指標仍然有效。

記憶體分配的幾個注意細節: 1.不能多次釋放 2.釋放完之後(指標仍然有值),給指標置NULL,標誌釋放完成 3.記憶體洩露(p重新賦值之後,再free,並沒有真正釋放記憶體)

相關文章