1.基本概念
堆(Heap)
程序可以動(dòng)態(tài)申請(qǐng)的存儲(chǔ)空間躺酒,通過malloc系列函數(shù)分配,全局可訪問蔑歌。棧(Stack)
這里說的棧不是數(shù)據(jù)結(jié)構(gòu)中LIFO的棧羹应,而是進(jìn)程虛擬地址空間的棧;程序在進(jìn)行函數(shù)調(diào)用時(shí)動(dòng)態(tài)伸縮的存儲(chǔ)空間次屠,局限于函數(shù)內(nèi)可以訪問园匹。
-堆變量(Heapvariables)
數(shù)據(jù)存儲(chǔ)在堆的變量雳刺,全局可訪問。
棧變量(Stackvariables)
函數(shù)中聲明的局部變量裸违,只能在函數(shù)內(nèi)部訪問掖桦,否則訪問行為的結(jié)果是未定義的。指針參數(shù)(Pointerparameters)
參數(shù)類型為指針的參數(shù)供汛。非指針參數(shù)(Non-pointerparameters)
參數(shù)類型不是指針的參數(shù)枪汪。
2.進(jìn)程的虛擬地址空間
3.相關(guān)問題剖析
3.1 如何正確的分配內(nèi)存
demo代碼
void * fun_m1()
{
char buf[100];
return (void *)buf;
}
void * fun_m2(size_t size)
{
return malloc(size);
}
void fun_m3(size_t size, void * p)
{
p = malloc(size);
}
void fun_m4(size_t size, void ** p)
{
*p = malloc(size);
}
剖析
- fun_m1是錯(cuò)誤的,因?yàn)樗祷氐臈W兞康牡刂氛颍绻麑?duì)它指向的地址進(jìn)行讀寫雀久,程序行為的結(jié)果是未定義的,程序很可能崩潰趁舀,因?yàn)榇藭r(shí)棧變量的空間已經(jīng)被回收(棧頂指針改變了)岸啡。
- fun_m2是正確的,因?yàn)樗祷氐氖莔alloc申請(qǐng)的堆空間的地址赫编。
- fun_m3和fum_m4很具有迷惑性,要分區(qū)fun_m3和fun_m4的區(qū)別奋隶,我們這里需要澄清一個(gè)概念:任何的參數(shù)傳遞本質(zhì)上都是值拷貝擂送,任何參數(shù)都是棧變量。
- 在我們以往觀念中參數(shù)傳遞就是兩種:值傳遞唯欣,指針傳遞嘹吨,而通過指針可以改變指針指向的變量。
- 為什么說參數(shù)傳遞都是值拷貝呢境氢,這是因?yàn)椴还軈?shù)是否為指針蟀拷,傳遞的都是一份值的拷貝,只不過當(dāng)你的參數(shù)類型為指針時(shí)萍聊,你傳遞的是指針變量的值问芬,而通過*操作符作用在指針變量上,你又剛好可以影響到指針變量關(guān)聯(lián)的其他變量的值寿桨。
- 通過上面的剖析我們可以知道fun_m3是錯(cuò)誤的此衅,因?yàn)闆]有*操作符作用在p上,單純對(duì)p賦值操作只會(huì)影響到局部的棧變量p的值亭螟,而不會(huì)對(duì)函數(shù)fun_m3外的變量有任何影響挡鞍。fun_m4是正確的,因?yàn)橛?操作符作用在p上预烙,通過對(duì)*p賦值來修改傳遞給p的參數(shù)墨微,使它指向申請(qǐng)的堆空間。
3.2 如何判斷堆和棧的“增長(zhǎng)”方向(從低到高扁掸,還是從高到低)
判斷棧的“增長(zhǎng)”方向
#include <stdio.h>
#include <malloc.h>
void fun1(int * pb)
{
int a;
printf("stack alloc direction[%s]\n", &a > pb ? "Up" : "Down");
}
void fun2()
{
int b;
fun1(&b);
}
int main()
{
fun2();
return 0;
}
編譯運(yùn)行
[root@iZ940zytujjZ test]# gcc -o test10 test10.c
[root@iZ940zytujjZ test]# ./test10
stack alloc direction[Down]
[root@iZ940zytujjZ test]#
從運(yùn)行結(jié)果看翘县,棧的增長(zhǎng)方向是“從高到低”(Down)最域。
判斷堆的“增長(zhǎng)”方向
#include <stdio.h>
#include <unistd.h>
#include <malloc.h>
int main()
{
void * a = sbrk(10); //調(diào)整堆頂指針brk
void * b = sbrk(20);
printf("heap alloc direction[%s]\n", b > a ? "Up" : "Down");
return 0;
}
編譯運(yùn)行
[root@iZ940zytujjZ test]# gcc -o test11 test11.c
[root@iZ940zytujjZ test]# ./test11
heap alloc direction[Up]
[root@iZ940zytujjZ test]#
從運(yùn)行結(jié)果看,堆的增長(zhǎng)方向是“從低到高”(Up)炼蹦。