堆(Heap)
程序能夠動態申請的存儲空間,經過malloc系列函數分配,全局可訪問。數據結構
棧(Stack)
這裏說的棧不是數據結構中LIFO的棧,而是進程虛擬地址空間的棧;程序在進行函數調用時動態伸縮的存儲空間,侷限於函數內能夠訪問。函數
-堆變量(Heapvariables)
數據存儲在堆的變量,全局可訪問。spa
棧變量(Stackvariables)
函數中聲明的局部變量,只能在函數內部訪問,不然訪問行爲的結果是未定義的。指針
指針參數(Pointerparameters)
參數類型爲指針的參數。code
非指針參數(Non-pointerparameters)
參數類型不是指針的參數。進程
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是錯誤的,由於它返回的棧變量的地址,若是對它指向的地址進行讀寫,程序行爲的結果是未定義的,程序極可能崩潰,由於此時棧變量的空間已經被回收(棧頂指針改變了)。內存
fun_m2是正確的,由於它返回的是malloc申請的堆空間的地址。rem
fun_m3和fum_m4很具備迷惑性,要分區fun_m3和fun_m4的區別,咱們這裏須要澄清一個概念:任何的參數傳遞本質上都是值拷貝,任何參數都是棧變量。it
在咱們以往觀念中參數傳遞就是兩種:值傳遞,指針傳遞,而經過指針能夠改變指針指向的變量。io
爲何說參數傳遞都是值拷貝呢,這是由於無論參數是否爲指針,傳遞的都是一份值的拷貝,只不過當你的參數類型爲指針時,你傳遞的是指針變量的值,而經過*操做符做用在指針變量上,你又恰好能夠影響到指針變量關聯的其餘變量的值。
經過上面的剖析咱們能夠知道fun_m3是錯誤的,由於沒有*操做符做用在p上,單純對p賦值操做只會影響到局部的棧變量p的值,而不會對函數fun_m3外的變量有任何影響。fun_m4是正確的,由於有*操做符做用在p上,經過對*p賦值來修改傳遞給p的參數,使它指向申請的堆空間。
#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; }
[root@iZ940zytujjZ test]# gcc -o test10 test10.c
[root@iZ940zytujjZ test]# ./test10
stack alloc direction[Down]
[root@iZ940zytujjZ test]#
從運行結果看,棧的增加方向是「從高到低」(Down)。
#include <stdio.h> #include <unistd.h> #include <malloc.h> int main() { void * a = sbrk(10); //調整堆頂指針brk void * b = sbrk(20); printf("heap alloc direction[%s]\n", b > a ? "Up" : "Down"); return 0; }
[root@iZ940zytujjZ test]# gcc -o test11 test11.c
[root@iZ940zytujjZ test]# ./test11
heap alloc direction[Up]
[root@iZ940zytujjZ test]#
從運行結果看,堆的增加方向是「從低到高」(Up)。