內存區域劃分(地址由高到低)
//本節紅色註釋是在寫的時候有模糊或忘記的地方,藍色是該注意的地方
1.棧區
2.堆區
3.靜態(全局區)
4.常量區
5.代碼區
棧區:由系統分配,主要存一些局部變量(主要是定義在函數體內)這些內存在函數使用完後由系統釋放,例如如下函數
void printAb (int a, int b);
void printAb(int a, int b){
print("%d %d", a, b);
}
如上述a, b在函數printAb調用完後,這樣a,b便得到釋放
注:棧區內的數據以棧的形式存儲,棧的特點:先進後出
//棧區的函數返回棧區的數據,是不安全的;因爲棧區的數據隨着函數執行結束,也會由系統自動回收回去,不能夠保證一直都能夠使用
int comeBack() {
int x = 10;
return x;
}//不安全
靜態全局區:全局變量和static修飾的變量都由系統在靜態全局區內存放
靜態變量是用static定義的變量
如:
for(int i = 0 ; i < 5; i++){
static int a = 1;
a++;
printf("%d ", a);
}
這樣打印出的結果是2 3 4 5 6
注:用static修飾變量:存在於靜態全局區, 只能被初始化一次, 若沒有初始值,則默認爲0
靜態全局區的變量是在程序結束執行那時纔得到釋放,也是由系統自動分配,由系統分配.
常量區:主要存儲一些常量,如2, 3,4,yu ,"fdfd"等等
char *p = "ios";
*p = 'a'//這是錯的,指向常量區地址,修改的是常量區的地址,這是不允許的, 會發生崩潰的情況
注:常量區內的值只能讀取,不能修改
代碼區: 程序中的函數和語句被編譯成cpu指令存在於代碼區,代碼區也是由系統控制
堆區:由開發人員手動申請,手動控制
分配內存的函數
void *malloc(size_t); 返回值爲void *類型,這個被稱作是泛類型,泛類型可以轉換成任意一種指針類型,size_t是分配的字節數
int * p = malloc(sizeof(int)); p指向了一個分配一個整形大小的內存空間的首地址, p的地址是存在於棧區的,但是分配的地址是在堆區的,p裏面存的時一個堆區的地址.
在使用完內存之後要記得釋放
內存泄露:內存區域一直被佔用,得不到釋放
如下使用free(void *);
注:在釋放內存之後,如上面的 free(p); 需要使指針指向NULL(避免野指針)即 p = NULL;
這種釋放只是將該內存的標記設爲可用,而沒有清空裏面的內容(如果該內存沒有使用的時候標記爲0,一旦被分配即設爲1,這裏做的只是使裏面的1標誌設爲0).
void *calloc(n, size_t);
和malloc一樣,都是申請內存,並且calloc申請內存後,會對內存裏的內容做清空的操作;由於多了一步清空操作,效率要比malloc低. n:個數 size:字節數
calloc申請的內存字節數 = n * size;
eg: int *p6 = calloc(5, 4);
free(p6);
p6 = NULL;
void *realloc(p, size);
從p開始重新申請size個字節.
從地址p向後申請size個字節,如果後面可用的字節夠的話,就申請內存,並返回當前的指針p;如果不夠的話,會再去取內存中找一塊連續的空間,如果找到,就返回這一塊連續的空間的內存的首地址,並且把之前所佔用的內存釋放
int *p7 = malloc(2);
printf("%p\n", p7);
p7 = realloc(p7, 170);
printf("%p\n", p7);
以上是分配空間的還有如下幾個函數
void *memset(p,c , n);//從指針p的位置初始化n個字節的內存,把內容改成c
void *memcopy( p1,p2, n );//從指針p2的位置,向p1的位置,拷貝n個字節的內容
int memcmp(p1, p2, n);//比較p1和p2指向的內存所存放的內容是否相同,比較n個字節,相同返回爲0,不同返回差值
//棧區地址
int a = 3;
printf("&a = %p\n", &a);
//堆區地址
int *q = malloc(4);
printf("q = %p\n", q);
//靜態全局區
printf("a1 = %p\n", &b);
static int a2 = 2;
printf("a2 = %p\n", &a2);
//常量區
char *string = "happy";
printf("string = %p\n", string);
//代碼區
printHello();