接續(xù)上篇C語言基礎(chǔ)及指針④函數(shù)指針
在上一篇我們了解C語言中的函數(shù)及函數(shù)指針 景图, 使用函數(shù)指針 , 模擬了網(wǎng)絡(luò)請求的回調(diào)方式 , 今天我們來學(xué)習(xí)動態(tài)內(nèi)存分配骨坑。
我們在使用java的時候 锥咸, 所有的內(nèi)存都交由JVM做處理 狭瞎, 我們無法直接控制 , 雖然很少導(dǎo)致內(nèi)存溢出 搏予, 但是程序占用內(nèi)存卻會越來越大 熊锭, 所以我們在使用Android手機的時候 , 剛開始很流暢 雪侥, 用著用著就非惩胍螅卡 , 在打開大文件或是播放gif的時候 速缨, 如果采用java編寫處理引擎 锌妻, 則會比較卡 , 因為開辟的內(nèi)存空間無法控制 旬牲, GC回收又不是即時的 仿粹, 這時候就需要我們使用JNI技術(shù) , 使用C語言進行處理 原茅。接下來 吭历,我們就來學(xué)習(xí)C語言中的動態(tài)內(nèi)存分配 。
C語言中內(nèi)存的大致分配:
內(nèi)存 | 描述 | 特性 |
---|---|---|
棧區(qū) | 是一個確定的常數(shù)(win 1~2M) 不同平臺會有不同大小 超出會提示stackoverflow | 自動分配 擂橘, 自動釋放 |
堆區(qū) | 用于動態(tài)內(nèi)存分配 | 手動分配和釋放 晌区, 可占用80%內(nèi)存 |
全局區(qū)或靜態(tài)區(qū) | 在程序中明確被初始化的全局變量、靜態(tài)變量(包括全局靜態(tài)變量和局部靜態(tài)變量)和常量數(shù)據(jù)(如字符串常量) | 只初始化一次 |
程序代碼區(qū) | 代碼區(qū)指令根據(jù)程序設(shè)計流程依次執(zhí)行,對于順序指令朗若,則只會執(zhí)行一次(每個進程)恼五,如果反復(fù),則需要使用跳轉(zhuǎn)指令哭懈,如果進行遞歸唤冈,則需要借助棧來實現(xiàn)。 | 代碼區(qū)的指令中包括操作碼和要操作的對象(或?qū)ο蟮刂芬茫?/td> |
C語言中動態(tài)分配內(nèi)存是在堆區(qū) 银伟, java語言中new
一個對象 你虹, 也會在堆內(nèi)存中開辟一塊空間 , 來存儲我們創(chuàng)建的這個對象 彤避。在C語言中 傅物, 我們在堆區(qū)開辟一塊空間使用的關(guān)鍵字是malloc
, malloc
函數(shù)定義:
void* __cdecl malloc(
_In_ _CRT_GUARDOVERFLOW size_t _Size
);
使用如下:
// 動態(tài)內(nèi)存分配 琉预, 使用malloc函數(shù)在對內(nèi)存中開辟連續(xù)的內(nèi)存空間 , 單位是:字節(jié)
// 申請一塊40M的堆內(nèi)存
int* p = (int*)malloc(1024 *1024 * 10 * sizeof(int));
下面我們來模擬一下病毒:
/*動態(tài)內(nèi)存分配*/
void heapFunc() {
// 動態(tài)內(nèi)存分配 董饰, 使用malloc函數(shù)在對內(nèi)存中開辟連續(xù)的內(nèi)存空間 , 單位是:字節(jié)
// 申請一塊40M的堆內(nèi)存
int* p = (int*)malloc(1024 *1024 * 10 * sizeof(int));
}
void main() {
while (1)
{
// 睡一秒執(zhí)行一次
Sleep(1000);
heapFunc();
}
getchar();
}
打開任務(wù)管理器 , 我們可以看到我們共存所占內(nèi)存 圆米, 正在以40M每秒的速度 卒暂, 蹭蹭的往上漲 , 以前的蠕蟲病毒就是如此 娄帖, 不斷的消耗內(nèi)存 也祠, 然后導(dǎo)致系統(tǒng)崩潰 。
在使用靜態(tài)內(nèi)存分配的時候 近速, 內(nèi)存大小是固定的 诈嘿, 很容易超出棧內(nèi)存的最大值, 預(yù)估大小往往大大的超出使用大小 削葱, 浪費內(nèi)存 奖亚。使用malloc
申請內(nèi)存 , 最重要的一個點就是可以動態(tài)改變申請的內(nèi)存大小 析砸, 可以使用realloc
函數(shù)來重新申請內(nèi)存大小昔字,realloc
函數(shù)定義:
void* __cdecl realloc(
_Pre_maybenull_ _Post_invalid_ void* _Block,
_In_ _CRT_GUARDOVERFLOW size_t _Size
);
使用如下:
// 重新申請內(nèi)存大小 , 傳入申請的內(nèi)存指針 首繁, 申請內(nèi)存總大小
int* p2 = realloc(p, (len + add) * sizeof(int));
下面我們來應(yīng)用一下:
void main() {
int len;
printf("請輸入首次分配內(nèi)存大凶鞴:");
scanf("%d", &len);
// 動態(tài)分配內(nèi)存 , 內(nèi)存空間是連續(xù)的
int* p = (int*)malloc(len * sizeof(int));
// 給申請的內(nèi)存空間賦值
int i = 0;
for (; i < len ; i++)
{ // 生成隨機數(shù)賦值
p[i] = rand() % 100;
printf("array[%d] = %d , %#x\n", i, p[i], &p[i]);
}
// 在原有內(nèi)存上面蛮瞄,重新分配內(nèi)存大小
printf("請輸入增加的內(nèi)存大小");
int add;
scanf("%d", &add);
// 重新申請內(nèi)存大小 所坯, 傳入申請的內(nèi)存指針 谆扎, 申請內(nèi)存總大小
int* p2 = (int*)realloc(p, (len + add) * sizeof(int));
// 給新申請的內(nèi)存空間賦值
int j = len;
for (; j < len + add ; j++)
{
p2[j] = rand() % 200;
}
// 打印
j = 0;
for (; j < len + add; j++)
{
printf("array[%d] = %d , %#x\n", j, p2[j], &p2[j]);
}
// 回收申請的動態(tài)內(nèi)存
if (p2 != NULL)
{
free(p2);
p2 = NULL;
}
system("pause");
}
使用malloc
和realloc
配合 挂捅, 就可以模擬出我們java中的集合類型,動態(tài)改變內(nèi)存空間大小 。 使用malloc
第一次申請的內(nèi)存首地址和第二次申請的內(nèi)存首地址可能相同也可能不同 闲先, 因為申請的內(nèi)存是連續(xù)的 状土, 所有 , 但第一次申請的空間的后續(xù)空間不夠用時 伺糠, 會重新開辟新的空間 蒙谓, 并將數(shù)據(jù)copy到新的空間里面 。
內(nèi)存分配的幾個注意細(xì)節(jié):
1.不能多次釋放
2.釋放完之后 训桶, 給指針置NULL累驮,標(biāo)志釋放完成
3.內(nèi)存泄漏 (p重新賦值之后 , 再free 舵揭, 并沒有真正釋放 谤专, 要在賦值之前釋放前一個內(nèi)存空間)
Android程序員學(xué)C系列:
C語言基礎(chǔ)及指針①
C語言基礎(chǔ)及指針②之指針內(nèi)存分析
C語言基礎(chǔ)及指針③函數(shù)與二級指針
C語言基礎(chǔ)及指針④函數(shù)指針
C語言基礎(chǔ)及指針⑤動態(tài)內(nèi)存分配
C語言基礎(chǔ)及指針⑥字符操作
C語言基礎(chǔ)及指針⑦結(jié)構(gòu)體與指針
C語言基礎(chǔ)及指針⑧文件IO
C語言基礎(chǔ)及指針⑨聯(lián)合體與枚舉
C語言基礎(chǔ)及指針⑩預(yù)編譯及jni.h分析