C語言動態分配內存,malloc的出現就是來彌補靜態內存分配的缺點
比如說我們在定義數組的時候,數組的長度必須是一個常量,不能改變的值,假如我事先定義了數組,一旦業務需求發生改變,那么這個數組就不能再使用了。
傳統的數組定義也就是靜態分配,是不能夠手動釋放的,只能等待系統釋放,靜態分配的內存,是分配在棧中的,C語言中的函數調用也是通過棧來實現的,棧有一個特點就是先進后出,在調用函數的時候,是先壓入棧,然后從最上面的函數開始執行
我們先來看看內存四區,分別為堆區,棧區,數據區,代碼區,對於這四個區,做了以下總結
代碼區:
程序執行二進制碼(程序指令)
共享,只讀
數據區 :
初始化數據區(data)
未初始化數據區(bss)
常量區
棧區 :
系統為每一個程序分配一個臨時的空間,
局部變量,函數信息,函數參數,數組
棧區大小為:1M
在windows中可以擴展到10M
在linux中可以擴展到16M
堆區 :
存儲大數據,圖片,音樂,視頻
手動開辟 malloc
手動釋放 free
棧區大小為:1M,我們來驗證一下
int zhan[8200000] = { 0 };
在C語言中,我們定義了一個數組,長度為820000,那么我們知道,在棧中我們最多可分配1M的內存,我們可以計算一下,這八百二十萬的長度占了多大的內存,
定義的是int類型,所以8200000*4=32800000(字節)
得到的結果再除以1024,32800000/1024=32031.25(KB)
得到的結果再除以1024,32031.25/1024=31.280517578125(M)
大約是31M,最終運行起來,這個程序是會報錯的。
接下來我們就開辟堆內存存儲數據,這就用到了函數malloc
動態分配內存函數
malloc
使用函數之前我們要引用頭文件stdlib.h
#include<stdlib.h>
malloc函數語法示例
int* p1 = (int*)malloc(sizeof(int))
返回值類型為void* 類型,也就是指針類型,int* p1代表一個以int類型地址為內容的指針變量
int類型在內存中占用的大小為 4字節。
malloc括號中就是你要開辟的空間大小,單位是字節,分配一塊連續的區域
假如我要開辟一個空間,里面存儲5個數字,那么代碼如下
int* p1 = (int*)malloc(sizeof(int)*5);
這樣的格式可以更容易的理解,當然你也可以像下面這么寫
int* p1 = (int*)malloc(20);
如果地址開辟成功,返回一個內存地址,否則返回NULL,需要注意的是,如果開辟失敗了,那么在后邊的程序中調用,程序就會報錯,所以有時候還要加一個判斷條件,這點要注意
if (p1 == NULL) { printf("程序異常"); return -1; }
成功以后,我們可以使用這個內存空間,對它進行賦值。
在使用完之后,也可以調用free函數釋放,代碼如下
free(p1);
那么,當我們釋放這個p1之后,這個內存空間還能調用嗎?其實還可以調用的。在釋放之后,這個內存地址就變成了一個野指針,還可以進行賦值
為了避免野指針,在free(p1)后在加上一段代碼
p1 = NULL;
賦值為NULL,這個是可有可無的。
我們再來看一個函數,叫做內存操作函數
memset(),memcpy(),memmove(),
引用 string.h
#include<string.h>
1.memset()參數, void *memset(void *s, intc, size_tn);
我們來看看它的示例
int* p = (int*)malloc(sizeof(int) * 10); memset(p, 0, 40);
傳入p這個內存地址,重置為0,字節為40字節
它在重置為0時有效,並不是真正意義上的重置
這個函數作用通常是一串連續的內存一起操作,不會單獨對變量進行操作。
2.memcpy(),參數,void *memcpy(void *dest, constvoid *src, size_tn);
示例:
int arr[] = { 1,2,3,4,5,6,7,8,9 }; int* p = (int*)malloc(sizeof(int) * 9); memcpy(p, arr, sizeof(int) * 9);
arr存在棧內存中,p存在堆內存中,我們現在要把arr中的數復制到p中,這就用到了 memcpy()函數
用法:
memcpy(新數據,源數據,內存大小(字節))
它不同於strcpy()這個函數,strcpy()是字符串拷貝遇到\0會停止,而memcpy()拷貝的是內存,拷貝的內容和字節有關。
如果參數1和參數2的內存地址重疊,可能會導致程序報錯,應盡量避免
3.memmove()
memmove()功能用法和memcpy()一樣,區別在於:dest和src所指的內存空間重疊時,memmove()仍然能處理,不過執行效率比memcpy()低些。
4.memcmp(),參數,int memcmp(constvoid *s1, constvoid *s2, size_tn);
int arr[] = { 1,2,3,4,5,6,7,8,9 }; int arry[] = { 1,2,3,4,5 }; int value = memcmp(arr, arry, 20);
第一個參數和第二個參數進行比較,比較前20個字節,也就是前5個數,如果相等返回0,否則返回-1;
同樣可以比較字符串,代碼如下:
char arr[] = "hello\0 word"; char arry[] = "hello\0 word"; int value = memcmp(arr, arry, 11);