C語言 變數的儲存類

更新於 2022/11/10閱讀時間約 12 分鐘
● auto(自動)
● register(暫存器)
● static(靜態)
● extern(外部)
定義
作用範圍(scope)、儲存時期(life time)連結(linkage)的不同作為區別。

●作用範圍:分為區域變數(只能作用於其函數內)全域變數(作用於不同文件中)
接著我們來看看以下兩種程式碼哪個是可執行的。
#include "stdio.h"

void text(){
  printf("%d\n",a);
}

int main(void){
  int a = 0;
  text();
}
--------------------------------結果---------------------------------
’a’ was not declared in this scope
沒錯,這段程式碼是無法執行的,它會跑出一條’a’ was not declared in this scope的訊息,也就是a變數不存在於該區塊中。為什麼呢?我們可以發現,a的定義是在main這個主函數裡面,它是無法作用在其他函數內的,相反的我們在也可以發現,a也只會作用在main裡面,這就是所謂的區域變數。
#include "stdio.h"
int a = 1;
int main(void){
  printf("%d\n",a);
}
--------------------------------結果---------------------------------
1
而這段程式碼中,a是定義在任何函數外,就結果來說,我們可以正常看到它輸出了1。因此a的定義為全域變數,也就是在它定義開始一直到文件的最後一行,任何函式都可以使用a這個變數。
那如果,同時使用呢?
#include "stdio.h"

int a = 1;

int main(void){
  int a = 2;
  printf("%d\n",a);
}
--------------------------------結果---------------------------------
2
結果很明顯,輸出的會是2。由這點可知,局部變數在該函數中,作用的優先會大於全局變數,因此main函式中,a的變數會對應到函數內部,定義為2的a。

●存儲時期(life time):分為靜態存儲(直到整個程式結束前,該變數的值會持續保留,不受二次定義賦值影響)以及自動存儲(一旦該函式結束後,其變數就會消失)兩種。
一樣來看看這兩種的差別吧!
#include "stdio.h"

void text(){
  int a = 0;
  a++;
  printf("%d\n",a);
}

int main(void){
  text();
  text();
  text();
}
--------------------------------結果---------------------------------
1
1
1
結果輸出了不同行的三個1,這是為什麼呢?當main函數跑第一個text()的時候,text內部會創建一個a,並賦值0給a。接著第六行會讓a的值再加上1,也就是0+1=1。最後輸出a的值,並結束這個函數,同時刪掉a這個變數,注意喔!當函數結束後,裡面所有的變數都是會刪除的。因此,我們可以理解到,main使用text函式的三次中,a都會初始定義並賦值為0,所以這也是為什麼輸出的結果都是相同的,而這就是所謂的自動存儲
#include "stdio.h"

void text(){
  static int a = 0;
  a++;
  printf("%d\n",a);
}

int main(void){
  text();
  text();
  text();
}
--------------------------------結果---------------------------------
1
2
3
而這一次的執行可以得到不同行的1、2、3,為什麼加上static之後,就會這樣呢?當main在跑text第一次的時候,流程都跟前面講左方程式碼時一樣,但在最後輸出a的值之後,結束函數的同時並不會刪除掉a的值。並且在第二次跑text函數時,第五行不會重新賦值0給a,a變數仍舊保持著上一次結果的值,也就是1。因此在這次的text中,它會再次加1並輸出。最後我們可以理解到,函數在結束後,不會刪除掉有static描述的變數,並保持其值,而這就是所謂的靜態存儲

●連結(linkage):分為空連結(只能於函數內使用,區域變數)內部連結(可於定義並賦值位置一直到文件最後一行都可使用,類似全域變數)以及外部連結(可跨文件做使用)
讓我們測驗看看外部連結吧~
(text.c)
int b = 10;
(main.c)
#include "stdio.h"
int main(void){
  extern int b;
  printf("%d",b);
}
--------------------------------結果---------------------------------
10
當我在text.c檔案中定義一個變數b,只要在另外一個文件main.c當中,在定義類型前面再加一個extern修飾,就能跨文件使用變數了。在main.c執行後,即可成功輸出10。而這種方法,就是所謂的外部連結。
但要特別注意的是,外部連結必須是在同個資料夾,否則無法透過外部連結使用喔。

儲存類

●auto(自動)

auto擁有自動存儲區域變數空連結的特性,簡單來說就是auto只能修飾在函數內的變數,只能在函數內使用,且函數執行結束後就會消失。事實上,任何在函數內定義的變數,只要沒有特別修飾,直接定義類型、名稱及值後,就會自動修飾為auto。簡單來說就是auto在修飾上面,其實沒有特別用處。
#include "stdio.h"
int main(void){
  auto int b = 0;
  printf("%d",b);
}
--------------------------------結果---------------------------------
0
另外auto還有一個作用是,自動定義變數的類型,如下。
#include "stdio.h"

int main(void){
  auto b = 0;
  printf("%d",b);
}
--------------------------------結果---------------------------------
0
如果使用auto當定義類型時,它會自動幫b搜尋它適合的類型,也就是int。但如果沒有特別指定值的時候,變數則會默認為int。

●register(暫存器)

register擁有自動存儲區域變數空連結的特性,一樣是只能修飾在函數內的變數,它的特點在於,經過register修飾的變數,會存放在暫存器當中,而不是平常的記憶體內。因此它的執行速度會大幅提升,如下圖採用CR Ferreira的時間計算程式碼,計算有無register修飾的時間差。
#include "stdio.h"
#include "sys/time.h"
int main(void){
  double sum = 0;
  double add = 1;
  struct timeval begin, end;
  gettimeofday(&begin, 0);
  register int a,i;//暫存器變數
  for (i=0; i<1000000000; i++){//主要執行內容
    a++;
  }
  gettimeofday(&end, 0);
  long seconds = end.tv_sec - begin.tv_sec;
  long microseconds = end.tv_usec - begin.tv_usec;
  double elapsed = seconds + microseconds*1e-6;
  printf("Time measured: %.3f seconds.\n", elapsed);
  return 0;
}
--------------------------------結果---------------------------------
Time measured: 0.681 seconds.
-------------------------------分隔線--------------------------------
#include "stdio.h"
#include "sys/time.h"

int main(void){
  double sum = 0;
  double add = 1;
  struct timeval begin, end;

  gettimeofday(&begin, 0);
  int a,i;//一般變數

  for (i=0; i<1000000000; i++){//主要執行內容
  a++;
  }

  gettimeofday(&end, 0);
  long seconds = end.tv_sec - begin.tv_sec;
  long microseconds = end.tv_usec - begin.tv_usec;
  double elapsed = seconds + microseconds*1e-6;
  printf("Time measured: %.3f seconds.\n", elapsed);
  return 0;
}
--------------------------------結果---------------------------------
Time measured: 2.215 seconds.
可以清楚看出,有register修飾的文件,執行速度大幅領先無修飾的文件。

●static(靜態)

static擁有靜態區域變數、靜態全域變數兩種方式。前者只能在函數內修飾,並擁有靜態存儲、區域變數、空連結的特性後者只能在函數外修飾,擁有靜態存儲、全域變數、內部連結的特性
#include "stdio.h"
static int i;//靜態全域變數
void text(){
  static int j;//靜態區域變數
}
靜態區域變數的特性,在前面有說過,能夠在整個程式執行結束前,一直保有其值不會消失。這時候你可能會想,全域變數本來就是到程式執行結束才會消失,那還有必要寫static來修飾嗎?
確實,是如此沒錯,但全域變數跟靜態全域變數的最大差別在於連結性。一般沒做修飾的全域變數是可以跨文件利用extern做連結的,但經過static修飾的變數,則是無法跨文件取得,也就是內部連結,僅供該文件使用。
(text.c)
static int i = 5;
(main.c)
#include "stdio.h"
extern int i;
int main(void){
  printf("%d",i);
}
--------------------------------結果---------------------------------
當在main.c執行後,就無法取得i這個變數,也因此無法取得i的值,這就是static的內部連結性質。

● extern(外部)

一般在函數外未特別修飾的變數,擁有靜態存儲、全域變數、外部連結的特性,而extern則可以引用這些變數。相關實作在前方有示範過了,這邊就不多加掩飾。
參考內容
即將進入廣告,捲動後可繼續閱讀
為什麼會看到廣告
avatar-img
12會員
18內容數
這裡是來自 高科大 資管系二年級的學生,希望能在學習的過程中,也分享這些知識給大家。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
你可能也想看
Google News 追蹤
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
C#是一種開源、跨平台、面向對象的編程語言,具有類型安全、泛型、模式匹配等特性。廣泛應用於桌面和Web應用程序、遊戲開發、移動應用、雲計算等領域。全球數十萬家公司像微軟、Unity Technologies、Stack Overflow等使用C#支持其業務。C#還提供豐富的進階學習資源和主題。
Thumbnail
想要進入工程師的世界,首先要先學會架設自己的Build code環境,有了編譯環境,接下來就可以安心的撰寫你想要的C語言程式啦! 如果你不知道該從何下手,那不妨先照著本篇文章的步驟做,Violet一步一步教你並解釋每個步驟的意義,很快你就會得到一個能編譯C語言程式碼的虛擬基環境哦!
Thumbnail
在開發應用程式時,經常會遇到需要調整圖片大小以節省空間或加快加載速度的情況。本教學將介紹如何使用 C# 語言來壓縮圖片並調整其大小,以便在應用程式中使用。
Thumbnail
Ç在葡語被稱為「cedilha」。除了葡語之外,來看看還有哪些語言有這個符號吧!
Thumbnail
這篇文章將會從基本概述到射線偵測應用的詳細步驟,講述運用射線改變特定圖層中,射線命中的物件顏色。
Thumbnail
從基本功開始了解留存率是什麼?與遊戲跟玩家的關係怎麼看 留存代表第一天進入遊戲的玩家,在第二天時有多少人願意繼續玩遊戲, 假設第一天有 100 個新用戶加入遊戲,隔一天剩下 50 人,代表次日留存是 50 % 以此類推
Thumbnail
武漢肺炎猖獗,不僅打擊日本經濟,也重創日本兩位首相;加上自民黨內年輕議員對選情焦慮所引起的蝴蝶效應,讓日本朝野各黨各派使出混身解數以爭取可能到手的政權。 究竟這些日子以來,以及接下來的日本政局,發生什麼事?又要往哪裡發展? 本文為您解說箇中奧義。
耶稣的生平有点像传道书里的变数(就是有一小城、其中的人數稀少、有大君王來攻擊、修築營壘、將城圍困. 15 城中有一個貧窮的智慧人、他用智慧救了那城、卻沒有人記念那窮人. 16 我就說、智慧勝過勇力.然而那貧窮人的智慧、被人藐視、他的話也無人聽從 (传 9:14-16 CU5) ). 本来就是富足的
Thumbnail
進入我們python教學的第3天,正式要進入程式的教學了,首先當然要先從基礎的語法開始教起,我們必須基礎打穩,這樣往後在學進階程式的時候就能更得心應手,所以別略過基礎教學唷!!(程式碼位於文章下方)
Thumbnail
拜登代表的是歐巴馬/克林頓家族為首的全球自由主義者的最後建制派, 海岸大都會選民與自由主義者的代表, 賀錦麗代表的是印裔、黑裔的新興移民社群, 許多人擔心“親中拜登” 會讓中國續命, 但其實不是這樣的, 美國的基本國策已經穩固, 無論誰上都不會扭轉對華封鎖, 問題是手段與細節差異...
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
C#是一種開源、跨平台、面向對象的編程語言,具有類型安全、泛型、模式匹配等特性。廣泛應用於桌面和Web應用程序、遊戲開發、移動應用、雲計算等領域。全球數十萬家公司像微軟、Unity Technologies、Stack Overflow等使用C#支持其業務。C#還提供豐富的進階學習資源和主題。
Thumbnail
想要進入工程師的世界,首先要先學會架設自己的Build code環境,有了編譯環境,接下來就可以安心的撰寫你想要的C語言程式啦! 如果你不知道該從何下手,那不妨先照著本篇文章的步驟做,Violet一步一步教你並解釋每個步驟的意義,很快你就會得到一個能編譯C語言程式碼的虛擬基環境哦!
Thumbnail
在開發應用程式時,經常會遇到需要調整圖片大小以節省空間或加快加載速度的情況。本教學將介紹如何使用 C# 語言來壓縮圖片並調整其大小,以便在應用程式中使用。
Thumbnail
Ç在葡語被稱為「cedilha」。除了葡語之外,來看看還有哪些語言有這個符號吧!
Thumbnail
這篇文章將會從基本概述到射線偵測應用的詳細步驟,講述運用射線改變特定圖層中,射線命中的物件顏色。
Thumbnail
從基本功開始了解留存率是什麼?與遊戲跟玩家的關係怎麼看 留存代表第一天進入遊戲的玩家,在第二天時有多少人願意繼續玩遊戲, 假設第一天有 100 個新用戶加入遊戲,隔一天剩下 50 人,代表次日留存是 50 % 以此類推
Thumbnail
武漢肺炎猖獗,不僅打擊日本經濟,也重創日本兩位首相;加上自民黨內年輕議員對選情焦慮所引起的蝴蝶效應,讓日本朝野各黨各派使出混身解數以爭取可能到手的政權。 究竟這些日子以來,以及接下來的日本政局,發生什麼事?又要往哪裡發展? 本文為您解說箇中奧義。
耶稣的生平有点像传道书里的变数(就是有一小城、其中的人數稀少、有大君王來攻擊、修築營壘、將城圍困. 15 城中有一個貧窮的智慧人、他用智慧救了那城、卻沒有人記念那窮人. 16 我就說、智慧勝過勇力.然而那貧窮人的智慧、被人藐視、他的話也無人聽從 (传 9:14-16 CU5) ). 本来就是富足的
Thumbnail
進入我們python教學的第3天,正式要進入程式的教學了,首先當然要先從基礎的語法開始教起,我們必須基礎打穩,這樣往後在學進階程式的時候就能更得心應手,所以別略過基礎教學唷!!(程式碼位於文章下方)
Thumbnail
拜登代表的是歐巴馬/克林頓家族為首的全球自由主義者的最後建制派, 海岸大都會選民與自由主義者的代表, 賀錦麗代表的是印裔、黑裔的新興移民社群, 許多人擔心“親中拜登” 會讓中國續命, 但其實不是這樣的, 美國的基本國策已經穩固, 無論誰上都不會扭轉對華封鎖, 問題是手段與細節差異...