位元詩人 [C 語言] 程式設計教學:宣告和使用變數 (Variable)

C 語言變數
Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

前言

電腦程式大部分的工作都和資料處理相關。在程式語言中,變數 (variable) 相當於資料的標籤,我們可透過變數來操作資料。在本文中,我們介紹在 C 語言中使用變數的方式。

實字 (Literal)

實字是指直接寫死在程式裡的資料。在教學用範例程式裡時常會看到實字,因為從外界讀取資料的程式會比較複雜,直接使用程式內部寫好的資料則簡單得多。以下是一些實字的例子:

  • 12345 (整數)
  • 123.456 (浮點數)
  • "Hello World" (C 字串)
  • {1, 2, 3, 4, 5} (整數陣列)

宣告變數

C 語言的變數包含四個要件:

  • 資料型別 (data type)
  • 識別字 (identifier)
  • 值 (value)
  • 可視度 (scope)

絕大部分的程式語言都有資料型別的概念。資料型別用來規範資料在程式中合理的操作。我們在前一篇文章介紹過資料型別,此處不詳述。

在電腦程式中,編譯器或直譯器透過識別字來了解程式碼的意義。有些識別字是內建的,像是保留字 (keywords)、內建變數、內建函式、標準函式庫的函式等。有些識別字是程式設計者宣告後創造出來的,像是變數。

變數是資料的標籤,而非資料本身。電腦程式很大一部分是在操作資料,變數在本質上是用來操作資料的一種語法特性。

以下變數 i 的型別是 int,值為 3

int i = 3;

以下變數 s 的型別是指向 char 的指標,值為 C 字串 "Hello World"

char *s = "Hello World";

我們會在後續文章中介紹 C 語言的字元和字串,這裡先觀察一下變數的宣告方式即可。

使用變數

我們以簡短的例子來看如何使用變數:

#include <assert.h>                 /*  1 */
#include <stdio.h>                  /*  2 */

int main(void)                      /*  3 */
{                                   /*  4 */
    int a = 4;                      /*  5 */
    int b = 3;                      /*  6 */

    printf("4 + 3 = %d\n", a + b);  /*  7 */
    printf("4 - 3 = %d\n", a - b);  /*  8 */

    assert(a == 4);                 /*  9 */
    assert(b == 3);                 /* 10 */

    return 0;                       /* 11 */
}                                   /* 12 */

我們在第 5 行和第 6 行宣告整數型態變數 a 和另一個整數型態變數 b,並分別對兩變數賦值。變數對於 C 程式來說,是由程式設計者自行定義的,所以要先宣告才能使用。

接著,我們在第 7 行和第 8 行使用兩變數進行加法和減法運算,並將運算當成參數結果傳入 printf() 函式。實際的效果是在終端機印出運算結果。

最後,我們在第 9 行和第 10 行用 assert() 巨集確認變數 a 和變數 b 在運算過程中都沒有實質的變化。因為我們沒有把運算的結果回存到 ab 上。

在這個簡短的例子中,我們重覆使用 ab 多次。其實這兩個變數本身只是一個符號,我們透過這兩個變數操作整數形態資料 43

宣告常數 (Constant)

我們在宣告變數後,無法預防變數遭到預期外的修改。若確認某變數的值在整個程式中不會變化,可以加上 const 保留字來修飾該變數,這時候該變數視為常數。我們若在程式中修改常數,C 編譯器會引發錯誤,阻止程式編譯,藉此提醒程式設計者該修正程式碼了。

參考以下反例:

const double pi = 3.1415927;

pi = 4.0;  // Error!

我們宣告了型別為 double 的變數 pi,由於我們預期 pi 的值是定值,故加上 const 修飾 pi。事後我們意圖修改 pi 的值時,引發該程式的錯誤,這時候我們就知道程式碼出問題了。

由於 C 標準函式庫 math.h 已經定義了較精準的 pi 常數 M_PI,我們不應該另行宣告一個常數 pi。這裡只是展示 const 的用法。

合理的變數名稱

變數命名有固定的條件:

  • 第一個字元是字母或底線
  • 第二個以後的字元是字母、底線或數字

由於 C 語言會把一些新的保留字用首字底線的方式來命名,像 _Bool,目前不建議用首字底線來命名變數。除此之外,變數名稱有一些風格上的建議,詳見下一節。

變數的命名風格

撰碼風格 (coding style) 是讓程式碼易讀的一種撰碼方式,這是建議事項,而非強制的。變數命名風格也是撰碼風格的一環。以下是常見的變數命名風格:

  • PascalCase
  • camelCase
  • snake_case

Pascal case 在 C 語言甚少使用。但可考慮用來命名結構體 (structure) 或聯合體 (union),因為結構體或聯合體在概念上接近類別 (class)。

Camel case 在 C 語言也少用,這種風格主要在 Java 或 C# 圈子中流行。

C 語言常用 snake case 或是縮寫來命名變數或函式。像是 isalnum() 函式用來檢查某個字元是否為字串或數字。由 gtk_init() 的名稱可知,這是一個用來初始化的函式,並在函式名稱使用 gtk_ 前綴來模擬命名空間 (namespace)。

保留字 (Keywords)

保留字在程式碼中有特別的意義,故不能用來命名變數。這裡有一份 C 語言保留字的清單。原本的 C 語言使用小寫字當成保留字,現代 C 語言為了保持現有程式的相容性,新的保留字改以首字底線來命名,再加上選擇性的巨集宣告。

不要刻意背誦保留字,要在學習程式設計的過程中自然地學會。此外,好的程式碼編輯器會用顏色提示保留字所在的地方,我們可以很容易地看到保留字所在的位置。

可視度 (Scope)

可視度是一個隱含在程式碼中的概念。由小至大分為以下數種:

  • 區塊可見 (block scope)
  • 函式可見 (function scope)
  • 檔案可見 (file scope)
  • 全域可見 (global scope)

例如,下列整數型態變數 n 的可視度是函式可見:

int main(void)
{
    int n = 3;

    /* Use `n` here. */

    return 0;
}

下列無號整數型態變數 i 的可視度則是區塊可見:

int main(void)
{
    {
        size_t i;
        for (i = 0; i < 10; ++i) {
            /* Repeat something here. */
        }
    }

    /* `i` is not visible here. */

    return 0;
}

實際上,上述範例程式碼是在 ANSI C 中使用 for 迴圈的計數器的小技巧。在 C99 中則會改寫如下:

int main(void)
{
    for (size_t i = 0; i < 10; ++i) {
        /* Repeat something here. */
    }

    /* `i` is not visible here. */

    return 0;
}

剛開始學習 C 語言的時候,程式碼很簡短,不會感受到可視度的重要。當程式變長後,可視度的重要性會慢慢浮現出來。簡單的原則是僅開放最低限度的可視度,最好不要使用全域變數。

關於作者

身為資訊領域碩士,位元詩人 (ByteBard) 認為開發應用程式的目的是為社會帶來價值。如果在這個過程中該軟體能成為永續經營的項目,那就是開發者和使用者雙贏的局面。

位元詩人喜歡用開源技術來解決各式各樣的問題,但必要時對專有技術也不排斥。閒暇之餘,位元詩人將所學寫成文章,放在這個網站上和大家分享。