日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C語言深入講解棧與堆和靜態存儲區的使用_C 語言

作者:清風自在?流水潺潺 ? 更新時間: 2022-06-17 編程語言

一、程序中的棧

  • 棧是現代計算機程序里最為重要的概念之一
  • 棧在程序中用于維護函數調用上下文
  • 函數中的參數和局部變量存儲在棧上

?棧保存了一個函數調用所需的維護信息

  • 參數
  • 返回地址
  • 局部變量
  • 調用上下文

二、函數的調用過程

每次函數調用都對應著一個棧上的活動記錄

  • 調用函數的活動記錄位于棧的中部
  • 被調函數的活動記錄位于棧的頂部

三、函數調用的棧變化

從main() 開始運行

?main() 調用 f()

?當從 f() 調用中返回 main()

四、函數調用棧上的數據

  • 函數調用時,對應的棧空間在函數返回前是專用的
  • 函數調用結束后,棧空間將被釋放,數據不再有效

? ? ? ? 下面看一個指向棧數據的指針:?

#include <stdio.h>
 
int* g()
{
    int a[10] = {0};
    return a;
}
 
void f()
{
    int i = 0;
    int b[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int *pointer = g();
    
    for (i = 0; i < 10; i++)
    {
        b[i] = pointer[i];
    }
    for(i = 0; i < 10; i++)
    {
        printf("%d\n", b[i]);
    } 
}
 
int main()
{
    f();
    return 0;
}

? ? ? ? ?輸出結果如下:

? ? ? ? 如果把?

????????for (i = 0; i < 10; i++)

? ?????{

? ? ? ????????? b[i] = pointer[i];

? ?????}

????????注釋了,直接打印 pointer[i] 里面的數據,如下:

#include <stdio.h>
 
int* g()
{
    int a[10] = {0};
    return a;
}
 
void f()
{
    int i = 0;
    int b[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int *pointer = g();
    /*
    for (i = 0; i < 10; i++)
    {
        b[i] = pointer[i];
    }
    */
    for(i = 0; i < 10; i++)
    {
        printf("%d\n", pointer[i]);
    } 
}
 
int main()
{
    f();
    return 0;
}

? ? ? ? 輸出結果如下:

? ? ? ? ?為什么直接打印 pointer[i] 里面的值會是這樣呢?因為 pointer 指向的空間是棧空間,棧空間在 g() 函數返回之后,活動記錄就被釋放了。被釋放后調用 printf 函數,printf 函數需要在棧上面建立一個活動記錄。這個活動記錄就會有 printf 函數的參數信息和返回值等,所以 pointer 所指向的內存里面的數據由于 printf 函數的調用被改變了。因此,不能返回局部變量的地址,不能返回局部數組的數組名。

五、程序中的堆

  • 堆是程序中一塊預留的內存空間,可由程序自由使用
  • 堆中被程序申請使用的內存在被主動釋放前將一直有效

????????為什么有了棧還需要堆?

? ? ? ? 答:棧上的數據在函數返回后就會被釋放掉,無法傳遞到函數外部,如:局部數組

C語言程序中通過庫函數的調用獲得堆空間

  • 頭文件:malloc.h
  • malloc -- 以字節的方式動態申請堆空間
  • free -- 將堆空間歸還給系統

系統對堆空間的管理方式

空閑鏈表法,位圖法,對象池法等等

? ? ? ? 以?int* p = (int*)malloc(sizeof(int)); 為例,要申請 4 個字節的大小,遍歷之后發現跟 5 Bytes 這個節點最接近,找到一個可以用的單元之后,就將這個單元的地址返還給了 p 指針。以前也提過使用 malloc 申請內存空間時返回的內存空間可能比申請的實際內存空間要大一點點,原因就是在空閑鏈表管理堆空間這樣的系統里面,它會找最近的那個,找到后的一般都大于等于所需要的內存空間,假如?5 Bytes 這個節點下所有的空閑內存單元都用完的話,就會找?12 Bytes 節點下的內存單元,這樣malloc 返回的內存空間就有可能比自己實際申請的內存空間要大。

六、程序中的靜態存儲區

  • 靜態存儲區隨著程序的運行而分配空間
  • 靜態存儲區的生命周期直到程序運行結束
  • 在程序的編譯期靜態存儲區的大小就已經確定
  • 靜態存儲區主要用于保存全局變量和靜態局部變量
  • 靜態存儲區的信息最終會保存到可執行程序中

? ? ? ? 下面看一個靜態存儲區的驗證代碼:

#include <stdio.h>
 
int g_v = 1;
 
static int g_vs  = 2;
 
void f()
{
    static int g_vl = 3;
    
    printf("%p\n", &g_vl);
}
 
int main()
{
    printf("%p\n", &g_v);
    
    printf("%p\n", &g_vs);
    
    f();
    
    return 0;
}

? ? ? ? 輸出結果如下:

? ? ? ? ?可以看到這三個地址是順序存放的,因為這三個變量都是存放在程序的靜態存儲區,靜態存儲區在程序里面有固定的起始地址。?

七、小結

棧,堆和靜態存儲區是程序中的三個基本數據區

  • 棧區主要用于函數調用的使用
  • 堆區主要是用于內存的動態申請和歸還
  • 靜態存儲區用于保存全局變量和靜態變量

原文鏈接:https://blog.csdn.net/weixin_43129713/article/details/124093704

欄目分類
最近更新