C 語言變量在內存中的分佈情況

關於內存的基礎知識: 一個由C/C++編譯的程序佔用的內存分爲以下幾個部分:
    1. 棧區:由編譯器自動分配釋放,存放函數的參數值、返回值和局部變量,在程序運行過程中實時分配和釋放,棧區由操作系統自動管理,無須程序員手動管理。 
    2.堆區:堆是由malloc()函數分配的內存塊,使用free()函數來釋放內存,堆的申請釋放工作由程序員控制,容易產生內存泄漏。   
    3. 數據區:存放已初始化的全局變量、靜態變量(全局和局部)、常量數據。 
    4.BBS區:存放的是未初始化的全局變量和靜態變量。 
    5.代碼區:存放CPU執行的機器指令,代碼區是可共享,並且是隻讀的。
下面給出例子程序:       

#include <stdio.h>

#include <stdlib.h>
#include <string.h>
int y;                                                        全局未初始化變量  ================>BSS段
int f=7;                                                    全局已初始化變量  ================>數據段(data)
static int r;                                               全局未初始化的靜態變量  ==========>BSS段  
static int z=4;                                          全局已初始化的靜態變量  ==========>數據段(data)
int main (void)                                                                 ==================>函數是在內存的代碼段(text)裏分配
{
    static int n;                                          局部未初始化的靜態變量  ==========>BSS段
    static int m=6;                                     局部已初始化的靜態變量  ==========>數據段(data)
    auto int i;                                            局部未初始化的自動變量  ==========>
    auto int j=8;                                        局部已初始化的自動變量  ==========>棧
    char *temp;                                        局部未初始化的自動變量  ==========>棧
    char *p="it is string at rodata !";         局部已初始化的自動變量  ==========>數據段的只讀段(rodata) 
    printf("n=%d m=%d r=%d z=%d\n",n,m,r,z);
    printf("y=%d f=%d i=%d j=%d\n",y,f,i,j);
    temp=malloc(20*sizeof(char));           ============>在裏面分配內存空間;                    
    if (temp == NULL)  return -1;
    strcpy(temp,"hello everyone !");
    printf("p=%s\n temp=%s\n",p,temp);
    return 0;  
}
執行結果:
        
針對字符常量進行簡單是說明:
    實例如下:
#include <stdio.h>

int main (void)
{
    char *ptr = "hello world !" ;      //“hello world !”是代表字符串的地址,它本身存儲在數據的只讀數據段中;
    char ar[] = "hi everyone !";       //  "hi everyone !"  存儲在棧上; 
    printf("ptr1 = %s\n ar1 = %s\n",ptr,ar);
    //*ptr = 'H';  //如果未註銷,編譯時產生段錯誤;
    *ar = 'H';
    printf("ptr2 = %s\n ar2 = %s\n",ptr,ar);
    return 0;  
}
執行結果:
        

下面我們來看看變量的分類:
1.作用域角度分,有全局變量和局部變量它們採用的存儲類別如下:
          全局變量:靜態外部變量 、外部變量
          局部變量:自動變量、靜態局部變量、寄存器變量
2.從變量存在的時間分,有靜態存儲和動態存儲兩種類型;靜態存儲是指程序整個運行時期都存在,動態存儲是指程序被調用時被臨時分配;
          靜態存儲:靜態外部變量、靜態局部變量、外部變量
          動態存儲:自動變量、寄存器變量、形參變量
3.從變量值存放的位置來區分,
          內存中靜態存儲區:靜態外部變量、靜態局部變量、外部變量
          內存中動態存儲區:自動變量、形參變量
          CPU中的寄存器    :寄存器變量
    
¨對於局部變量來說,聲明存儲類型的作用是指定變量存儲的區域以及由此產生的生存期的問題,
¨對於全局變量來說,聲明存儲類型的作用是變量作用域的擴展問題。
nstatic 聲明一個變量的作用是:

(1) 局部變量static聲明,把它分配在靜態存儲區,該變量在整個程序執行期間不釋放,其所分配的空間始終存在。

(2) 全局變量static聲明,則該變量的作用域只限於本文件模塊(即被聲明的文件中)

nstatic對局部變量和全局變量的作用不同:

¨局部變量使變量由動態存儲方式改變爲靜態存儲方式
¨全局變量使變量局部化(局部於本文件)但仍爲靜態存儲方式
¨從作用域角度看凡有static聲明的其作用域都是侷限的或者是侷限於本函數內(靜態局部變量)或者侷限於本文件內(靜態外部變量)

1. auto存儲類型

    auto只能用來標識局部變量的存儲類型,對於局部變量,auto是默認的存儲類型,不需要顯示的指定。因此,auto標識的變量存儲在棧區中。

2.extern存儲類型

    extern用來聲明在當前文件中引用在當前項目中的其它文件中定義的全局變量。如果全局變量未被初始化,那麼將被存在BBS區中,且在編譯時,自動將其值賦值爲0,如果已經被初始化,那麼就被存在數據區中。全局變量,不管是否被初始化,其生命週期都是整個程序運行過程中,爲了節省內存空間,在當前文件中使用extern來聲明其它文件中定義的全局變量時,就不會再爲其分配內存空間。

3. register存儲類型 

    聲明爲register的變量在由內存調入到CPU寄存器後,則常駐在CPU的寄存器中,因此訪問register變量將在很大程度上提高效率,因爲省去了變量由內存調入到寄存器過程中的好幾個指令週期。

4. static存儲類型 

    被聲明爲靜態類型的變量,無論是全局的還是局部的,都存儲在數據區中,其生命週期爲整個程序,如果是靜態局部變量,其作用域爲一對{}內,如果是靜態全局變量,其作用域爲當前文件。靜態變量如果沒有被初始化,則自動初始化爲0。靜態變量只能夠初始化一次。

5.字符串常量
    字符串常量存儲在數據區中,其生存期爲整個程序運行時間,但作用域爲當前文件。

根據上面的幾種類型,比較他們的作用域、生存域和存儲位置的差異:
類型
作用域
生存域
存儲位置
auto 變量
一對{}內
當前函數
變量默認存儲類型,存儲在棧區
extern 函數
整個程序
整個程序運行期
變量默認存儲類型,代碼段
extern 變量
整個程序
整個程序運行期
初始化在data段,未初始化在BSS段
static 函數
當前文件
整個程序運行期
變量默認存儲類型,代碼段
static 全局變量
當前文件
整個程序運行期
初始化在data段,未初始化在BSS段
static 局部變量
一對{}內
整個程序運行期
初始化在data段,未初始化在BSS段
register變量
一對{}內
當前函數
運行時存儲在CPU寄存器中
字符串常量
當前文件
整個程序運行期
數據段

C語言程序的內存分配方式 
1.內存分配方式有三種:  
  [1]從靜態存儲區域分配。內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間都存在。例如全局變量,static變量。 
  [2]在棧上創建。在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。
          棧內存分配運算內置於處理器的指令集中,效率很高,但是分配的內存容量有限。 
  [3]從堆上分配,亦稱動態內存分配。程序在運行的時候用malloc或new申請任意多少的內存,程序員自己負責在何時用free或delete釋放內存。動態內存的生存期由程序員決定,使用非常靈活,但如果在堆上分配了空間,就有責任回收它,否則運行的程序會出現內存泄漏,頻繁地分配和釋放不同大小的堆空間將會產生堆內碎塊。

根據上面的描述繪出變量在內存中的存儲模型,如下圖:
    

總結:
    1.未初始化的全局自動變量和靜態變量(全局和局部)存儲在BSS段,在編譯時分配內存空間並被初始化爲0
    2.已初始化的全局自動變量和靜態變量(全局和局部)存儲在data段,在編譯時分配內存空間;常量數據被分配在rodata段
    3.局部自動變量和函數參數以及函數返回值存儲在棧上,在函數執行時計算機自動分配,無需程序員管理;
    4.庫函數(malloc free ··· )是在函數運行時分配在堆上,需要程序員自己分配與銷燬內存空間。


發佈了25 篇原創文章 · 獲贊 4 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章