C 堆變量,棧變量,指針參數,非指針參數 它們的區別你了解嘛

1.基本概念

  • 堆(Heap)
    程序可以動態申請的存儲空間,通過malloc系列函數分配,全局可訪問。

  • 棧(Stack)
    這里說的棧不是數據結構中LIFO的棧,而是進程虛擬地址空間的棧;程序在進行函數調用時動態伸縮的存儲空間,局限于函數內可以訪問。

-堆變量(Heapvariables)
數據存儲在堆的變量,全局可訪問。

  • 棧變量(Stackvariables)
    函數中聲明的局部變量,只能在函數內部訪問,否則訪問行為的結果是未定義的。

  • 指針參數(Pointerparameters)
    參數類型為指針的參數。

  • 非指針參數(Non-pointerparameters)
    參數類型不是指針的參數。

2.進程的虛擬地址空間

進程虛擬地址空間

3.相關問題剖析

3.1 如何正確的分配內存

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是錯誤的,因為它返回的棧變量的地址,如果對它指向的地址進行讀寫,程序行為的結果是未定義的,程序很可能崩潰,因為此時棧變量的空間已經被回收(棧頂指針改變了)。
  • fun_m2是正確的,因為它返回的是malloc申請的堆空間的地址。
  • fun_m3和fum_m4很具有迷惑性,要分區fun_m3和fun_m4的區別,我們這里需要澄清一個概念:任何的參數傳遞本質上都是值拷貝,任何參數都是棧變量。
  • 在我們以往觀念中參數傳遞就是兩種:值傳遞,指針傳遞,而通過指針可以改變指針指向的變量。
  • 為什么說參數傳遞都是值拷貝呢,這是因為不管參數是否為指針,傳遞的都是一份值的拷貝,只不過當你的參數類型為指針時,你傳遞的是指針變量的值,而通過*操作符作用在指針變量上,你又剛好可以影響到指針變量關聯的其他變量的值。
  • 通過上面的剖析我們可以知道fun_m3是錯誤的,因為沒有*操作符作用在p上,單純對p賦值操作只會影響到局部的棧變量p的值,而不會對函數fun_m3外的變量有任何影響。fun_m4是正確的,因為有*操作符作用在p上,通過對*p賦值來修改傳遞給p的參數,使它指向申請的堆空間。

3.2 如何判斷堆和棧的“增長”方向(從低到高,還是從高到低)

判斷棧的“增長”方向

#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)。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,740評論 18 399
  • C語言中內存分配 在任何程序設計環境及語言中,內存管理都十分重要。在目前的計算機系統或嵌入式系統中,內存資源仍然是...
    一生信仰閱讀 1,180評論 0 2
  • 原文地址:C語言函數調用棧(一)C語言函數調用棧(二) 0 引言 程序的執行過程可看作連續的函數調用。當一個函數執...
    小豬啊嗚閱讀 4,665評論 1 19
  • 一早買韭菜,是二元一捆,我讓老板給我找一小捆,就一小捆看上去也不少,回到辦公室分給同事一部分,分享是快樂的!
  • 李逸風從楚天鬼手二人眼里看見了只有饑餓的野獸盯著食物時才會出現的眼神,那是他們對勝利的渴望,所以李逸風索性不再去關...
    RainyMorning閱讀 292評論 0 0