動(dòng)態(tài)內(nèi)存分配
我們需要?jiǎng)討B(tài)內(nèi)存分配的原因
- C語(yǔ)言中的一切操作都是基于內(nèi)存的
- 變量和數(shù)組都是內(nèi)存的別名兵罢,如何分配這些內(nèi)存由編譯器在編譯期間決定
- 定義數(shù)組的時(shí)候必須指定數(shù)組長(zhǎng)度
- 而數(shù)組長(zhǎng)度是編譯器期就必須決定的
袍辞! 需求
程序運(yùn)行的過(guò)程中允悦,可能需要使用一些額外的內(nèi)存空間
malloc和free
- malloc所分配的是一塊連續(xù)的內(nèi)存挪鹏,以字節(jié)為單位,并且不帶任何的類型信息
- free用與動(dòng)態(tài)歸還
注意
- malloc實(shí)際分配的內(nèi)存可能會(huì)比請(qǐng)求的稍微多一點(diǎn)赘被,但是不能依賴于編譯器的這個(gè)行為
- 當(dāng)請(qǐng)求的動(dòng)態(tài)內(nèi)存無(wú)法滿足時(shí)malloc返回NULL
- 當(dāng)free參數(shù)為NULL時(shí)候衰伯,函數(shù)直接返回
calloc和realloc
- void* calloc(size_t num,size_t size)(單元的數(shù)量,單元的大惺濉)
- void* realloc(void* pointer,size_t new_size)(指向之前已經(jīng)分配的內(nèi)存新的內(nèi)存需要的內(nèi)存)重置動(dòng)態(tài)內(nèi)存空間的大刑枰健)
程序的三個(gè)要素
棧
后進(jìn)先出
- 棧是現(xiàn)代計(jì)算機(jī)程序最為重要的概念之一
- 棧在程序中用于維護(hù)函數(shù)的調(diào)用上下文,沒(méi)有棧就沒(méi)有函數(shù)算色,沒(méi)有局部變量
- 棧保存了一個(gè)函數(shù)調(diào)用所需要的維護(hù)信息
- 函數(shù)參數(shù)抬伺,函數(shù)返回地址
- 局部變量
- 函數(shù)調(diào)用上下文
tips:不能將一個(gè)指針指向一個(gè)局部變量
堆
堆內(nèi)存需要主動(dòng)申請(qǐng)
- 為什么有了棧還需要堆?
- 棧上的數(shù)據(jù)在函數(shù)返回后就會(huì)被釋放掉灾梦,無(wú)法傳遞到函數(shù)外部峡钓,如局部變量
- 堆是程序中一塊巨大的內(nèi)存空間,可由程序自由支配
- 堆中被程序申請(qǐng)使用的內(nèi)存在程序主動(dòng)釋放前將一直有效
- 系統(tǒng)對(duì)堆的管理方式
- 空閑列表法若河,位圖法能岩,對(duì)象池法等等
程序的靜態(tài)存儲(chǔ)區(qū)
- 程序的靜態(tài)存儲(chǔ)區(qū)隨著程序的運(yùn)行而分配空間,直到程序運(yùn)行結(jié)束
- 在程序編譯期間靜態(tài)存儲(chǔ)區(qū)的大小就已經(jīng)確定
- 程序的靜態(tài)存儲(chǔ)區(qū)主要用于保存程序中的全局變量和靜態(tài)變量
- 與棧和堆不同萧福,靜態(tài)存儲(chǔ)區(qū)的信息最終會(huì)保存在可執(zhí)行程序中
小結(jié)
- 棧拉鹃,堆和靜態(tài)存儲(chǔ)區(qū)是C語(yǔ)言常設(shè)計(jì)的三個(gè)基本區(qū)
- 棧區(qū)是主營(yíng)帥帥函數(shù)的調(diào)用的使用
- 堆區(qū)主要是用來(lái)內(nèi)存的動(dòng)態(tài)申請(qǐng)和歸還
- 靜態(tài)存儲(chǔ)區(qū)用于保存全局變量和靜態(tài)變量
程序的內(nèi)存布局
- 代碼在可執(zhí)行程序中的對(duì)應(yīng)位置
- File Header告訴系統(tǒng)則是個(gè)可執(zhí)行的文件
- data段用來(lái)存儲(chǔ)有初始化的數(shù)據(jù)
- bss段用來(lái)存放沒(méi)有初始化的數(shù)據(jù)
- text段是代碼段
程序文件的一般布局
程序的內(nèi)存布局(運(yùn)行的時(shí)候,由操作系統(tǒng)分配)
各個(gè)段的作用
- 堆棧段在程序運(yùn)行后才正式存在鲫忍,是程序運(yùn)行的基礎(chǔ)(最先建立的原因是因?yàn)榛顒?dòng)進(jìn)程)
- .bss段存放的是未初始化的全局變量和靜態(tài)變量
- .text段存放的是程序中的可執(zhí)行的代碼
- .dada段存放的是程序中已經(jīng)初始化的全局變量和靜態(tài)變量(必須要寫(xiě)到程序文件里面去)
- .rodata段存放程序中的常量值毛俏,如字符串常量(只讀數(shù)據(jù)段)
.bss和.data段就是所謂的靜態(tài)存儲(chǔ)區(qū)
小結(jié)
- 靜態(tài)存儲(chǔ)區(qū)指的是.bss和.data
- 只讀區(qū)指的是.rodata
- 局部變量所占用的空間為棧上空間
- 動(dòng)態(tài)空間為堆空間
- 程序可執(zhí)行代碼存放與.text段
頭疼的野指針(了解野指針)
- 野指針通常是因?yàn)橹羔樧兞恐斜4娴闹?strong>不是一個(gè)合法的內(nèi)存地址而造成的
- 野指針不是NULL,是一個(gè)指向不可用內(nèi)存的指針
- NULL指針不容易弄錯(cuò)饲窿,可以通過(guò)if來(lái)判斷是否為NULL指針
C語(yǔ)言中沒(méi)有方法可以判斷是否為野指針
野指針的由來(lái)
- 局部指針變量沒(méi)有被初始化例子1
- 使用已經(jīng)釋放后的指針例子2
- 指針?biāo)赶虻淖兞吭谥羔樦氨讳N毀例子3
最佳示例 例子1
#include <stdio.h>
#include <string.h>
struct Student
{
char* name;
int number;
};
int main()
{
struct Student s;
strcpy(s.name, "Delphi Tang"); // OOPS!
s.number = 99;
return 0;
}
最佳示例 例子2
#include <stdio.h>
#include <malloc.h>
#include <string.h>
void func(char* p)
{
printf("%s\n", p);
free(p);
}
int main()
{
char* s = (char*)malloc(5);
strcpy(s, "Delphi Tang");
func(s);
printf("%s\n", s); // OOPS!
return 0;
}
最佳示例
#include <stdio.h>
char* func()
{
char p[] = "Delphi Tang";
return p;
}
int main()
{
char* s = func();
printf("%s\n", s); // OOPS!
return 0;
}
經(jīng)典的錯(cuò)誤(4野指針)
非法內(nèi)存操作分析
- 結(jié)構(gòu)體成員指針沒(méi)有初始化
- 沒(méi)有為結(jié)構(gòu)體指針?lè)峙渥銐虻膬?nèi)存
例子
#include<stdio.h>
#include<malloc.h>
struct Demo
{
int * p;
};
void main()
{
struct Dome d1;
struct Dome d2;
int i=0;
for(i=0;i<10;i++) //問(wèn)題1:不能直接賦值煌寇,因?yàn)椴](méi)有分配內(nèi)存,也沒(méi)有初始化逾雄。
{
d1.p[i]=i+1;
}
free(d2.p);
d2.p=(int *)calloc(5,sizeof(int));
for(i=0;i<10;i++) //問(wèn)題2:只分配了5個(gè)空間阀溶,卻用了10個(gè)腻脏。
{
d2.p[i]=i+1;
}
free(d2.p);
return 0;
}
內(nèi)存初始化分析
- 內(nèi)存分配成功但是沒(méi)有初始化
#include<stdio.h>
#include<malloc.h>
void main()
{
char* s=(char*)malloc(5);//不一定是 \0結(jié)束,所以不是字符串银锻。沒(méi)辦法輸出
//s[4]='\0';
printf(s);
free(S);
}
內(nèi)存越界
- 數(shù)組越界
void f(int a[10])
{
int i=0;
for(i=0;i<10;i++)
{
a[i]=i;
printf("%d\n",a[i]);
}
}
int main()
{
int a[5];
f(a);
return 0;
}
內(nèi)存泄漏分析
#include <stdio.h>
#include <malloc.h>
void f(unsigned int size)
{
int* p = (int*)malloc(size*sizeof(int));
int i = 0;
if( size % 2 != 0 )
{
return; // OOPS!需要free掉永品,基數(shù)個(gè)size的情況
}
for(i=0; i<size; i++)
{
p[i] = i;
printf("%d\n", p[i]);
}
free(p);
}
int main()
{
f(9);
f(10);
return 0;
}
C語(yǔ)言有關(guān)內(nèi)存的規(guī)則
用malloc申請(qǐng)了內(nèi)存之后,應(yīng)該立即檢查指針值是否為NULL击纬,防止使用值為NULL的指針
int *p=(int *)malloc(5*sizeof(int));
if(p!=NULL)
{
}
free(p);