C語言變數與資料型別完整解說|從基礎到實作,適合初學者

目次

1. 前言

C 語言中變數與資料型別的重要性

C 語言是一種廣泛用於系統程式設計與嵌入式系統開發的程式語言。在學習 C 語言時,「變數」與「資料型別」 是最基本且重要的概念。程式是透過操作資料而成立,為了適當管理這些資料,需要正確使用變數,並選擇適當的資料型別。 例如,當考慮用於儲存數值的變數時,處理整數與處理小數時所使用的資料型別不同。此外,為了節省記憶體與提升處理速度,選擇最適的資料型別也是很重要的。

本文的目的

本文將針對 C 語言的「變數」「資料型別」,以初學者也能易於理解的方式說明。為了能系統性地學習從基本概念到實務用法,將依照以下重點說明。
  1. 什麼是變數? - 說明宣告與初始化的方法、命名規則等
  2. 資料型別的分類 - 基本資料型別(int、float、char 等)與衍生資料型別(結構體、陣列、指標 等)
  3. 型別轉換(轉型) - 隱式型別轉換與顯式型別轉換
  4. 變數的作用域與生命週期 - 區域變數與全域變數的差異
  5. 實務上資料型別的選擇方式 - 考慮記憶體使用量與計算精度的最佳選擇

在什麼情況下需要注意變數與資料型別?

在 C 語言程式設計中,以下情況下變數與資料型別的選擇相當重要。

記憶體最佳化

在嵌入式系統與低階程式中,需要將記憶體使用量降至最低。因此,適當選擇資料型別即可防止不必要的記憶體消耗。
short num1 = 100;  // 2 位元組(16 位元)
int num2 = 100;    // 4 位元組(32 位元)
在上述例子中,使用 short 可比 int 節省記憶體。

提升計算精度

在處理浮點數時,float 不如 double 精度高,但會消耗更多記憶體。
float pi = 3.141592;  // 單精度浮點數(32 位元)
double pi_high = 3.14159265358979;  // 雙精度浮點數(64 位元)
在需要高精度的計算中,通常會使用 double

透過型別轉換防止錯誤

在 C 語言中,不同資料型別之間的運算可能會自動進行型別轉換。若未適當進行轉型,可能會產生非預期的結果。
int a = 10;
float b = 3.5;
int result = a + b;  // 隱式型別轉換(結果會被截斷為 int 型別)
在此情況下,result 的值會變成 13,小數點以下會被截斷。為了防止此情況,需要使用顯式型別轉換(轉型)。
float result_correct = (float)a + b;  // 正確的型別轉換

總結

在 C 語言程式設計中,變數與資料型別的選擇極為重要。考慮記憶體效率、計算精度與型別轉換的影響,適當選擇資料型別即可防止錯誤,並撰寫高效能的程式

2. 什麼是變數?

變數的基本概念

在 C 語言中,變數(Variable) 是程式用來暫時保存資料的「具名記憶區域」。在程式內進行計算或保存資料時,適當使用變數即可撰寫彈性的程式碼。

變數的特徵

  • 用於保存資料的記憶區域
  • 在程式執行期間可變更其值
  • 根據資料類型(型別)分配記憶空間
例如,有用來保存整數、浮點數、字元等的變數。

變數的宣告與初始化

在 C 語言中使用變數,首先需要 變數的宣告。在變數宣告時,需要指定 資料型別(型別)與變數名稱

變數的基本宣告方式

資料型別 變數名;

變數的初始化

僅僅宣告變數,值仍未定義。因此,透過 初始化(設定初始值) 可防止意外的行為。
int num = 10;  // 整數型變數 num 以 10 初始化
float pi = 3.14;  // 浮點型變數 pi 以 3.14 初始化
char letter = 'A';  // 字元型變數 letter 以 'A' 初始化

C 語言的變數型別

在 C 語言中,需要明確定義變數的型別。主要的資料型別如下。
資料型別說明使用範例
int整數型int a = 10;
float單精度浮點數float b = 3.14;
double雙精度浮點數double c = 3.1415926535;
char字元型char d = 'A';
關於整數型與浮點型的差異,將在後續「資料型別概述」章節中詳細說明。

變數名稱的命名規則與最佳實踐

C 語言的變數名稱規則

變數名稱可以自由設定,但必須遵守以下規則。 ✅ 可使用的字元
  • 英文字母(A-Za-z
  • 數字(0-9) ※但 變數名稱開頭不可使用
  • 底線(_
🚫 不可使用的項目
  • 保留字(例:intfloatreturn 等)
  • 特殊字元(例:@, #, $ 等)
  • 變數名稱開頭為數字
int _value = 10;  // OK
int number1 = 20;  // OK
int 1st_number = 30;  // NG(數字開頭的變數名稱不可)
int return = 100;  // NG(保留字不可使用)

考慮可讀性的命名(最佳實踐)

在 C 語言中,適當命名變數可提升程式碼的可讀性。 ✅ 良好範例
int userAge;  // 使用者的年齡
float circleArea;  // 圓的面積
char firstLetter;  // 最初的字元
🚫 不良範例
int a;  // 意義不明
float b1;  // 不知道什麼資料
char x_y_z;  // 過於複雜
👉 提升可讀性的要點
  • 變數名稱要具備意義
  • 多個單詞使用camelCase(例:userAge)或snake_case(例:user_age)
  • 盡量避免縮寫(例:如 numOfStudents 具體化)

變數的使用方式(簡易程式)

以下程式使用變數進行簡單計算,並顯示結果。

範例程式碼

#include <stdio.h>

int main() {
    int a = 5;
    int b = 10;
    int sum = a + b;  // 使用變數計算

    printf("a = %d, b = %d, sum = %dn", a, b, sum);
    return 0;
}

執行結果

a = 5, b = 10, sum = 15
透過使用變數,可將計算結果儲存並再次利用。

總結

  • 變數是暫時保存資料的記憶區域
  • 在 C 語言中,宣告變數時必須指定資料型別
  • 變數命名有規則,建議以可讀性為考量命名
  • 使用變數可讓資料更易於管理

3. C語言的資料型概述

資料型是什麼?

C語言中,資料型(Data Type) 透過明確指定,可決定變數所處理的資料類型與記憶體使用量。選擇適當的資料型,可實現記憶體效能化型別轉換導致的錯誤防止

C語言的資料型特點

明確資料的種類(整數、浮點數、字元等) ✅ 最佳化記憶體使用量(每種型別使用的記憶體大小不同) ✅ 決定型別轉換與運算時的行為(整數之間的計算、小數的計算等) 例如,如下整數型與浮點型可處理的資料不同。
int age = 25;        // 整數(只能儲存整數值)
float pi = 3.14;     // 浮點數(可處理小數)
char letter = 'A';   // 字元型(只能儲存單一字元)

C語言的資料型分類

C語言的資料型大致可分為 基本資料型衍生資料型 兩類。
資料型的種類概述
基本資料型變數的基本型別(int, float, char 等)
衍生資料型由基本資料型組合而成(陣列、結構體、指標等)

基本資料型

基本資料型是 C 語言程式中最常使用的資料型別。

整數型(Integer)

用於處理整數的資料型別,可儲存正負值。
資料型記憶體大小(標準)可儲存值的範圍(32 位元環境)
int4 位元組(32 位元)-2,147,483,648 ~ 2,147,483,647
short2 位元組(16 位元)-32,768 ~ 32,767
long4~8 位元組依環境而定(範圍比 int 更廣)
unsigned int4 位元組0 ~ 4,294,967,295
int number = 100;
short smallNumber = 10;
unsigned int positiveOnly = 300;

浮點型(Floating Point)

用於處理小數的資料型別,依精度不同分為 floatdouble
資料型記憶體大小精度
float4 位元組約 6~7 位數
double8 位元組約 15 位數
long double10~16 位元組約 18 位數以上
float pi = 3.14f;  // 加上 "f" 可為 float 型別
double precisePi = 3.1415926535;

字元型(Character)

用於儲存單一字元的資料型別,實際上會被視為 整數(ASCII 碼)
資料型記憶體大小可儲存的資料
char1 位元組‘A’, ‘b’, ‘9’ 等單一字元
char letter = 'A';
printf("%c", letter);  // 輸出 A
因被視為 ASCII 碼,可將 char 作為數值進行運算。
char letter = 'A';
printf("%d", letter);  // 65('A' 的 ASCII 碼)

衍生資料型

衍生資料型用於定義結合基本資料型的高階資料結構。
資料型說明
陣列(Array)連續儲存相同型別的資料
結構體(struct將不同型別的資料作為一個單位處理
共用體(union共享記憶體的資料結構
列舉型(enum定義有意義的常數
指標(Pointer)儲存記憶體位址的變數

資料型的選擇基準

選擇適當的資料型會影響程式的效能與記憶體管理
使用情境建議資料型理由
迴圈計數器unsigned int不需要符號且效率佳
高精度計算doublefloat 精度更高
想節省記憶體short / char以最小必要尺寸管理
處理字串的單一字元char以 1 位元組管理字元
for (unsigned int i = 0; i < 100; i++) {
    printf("%d ", i);
}

總結

  • C語言的資料型包括 基本資料型(整數型、浮點型、字元型)與 衍生資料型(陣列、結構體、指標 等)。
  • 選擇適當的資料型可提升程式的效能。
  • 整數型通常使用 int,浮點型則常用 double
  • 善用衍生資料型,可更容易處理複雜的資料結構。

4. 基本資料型(原始型)

什麼是基本資料型?

C 語的基本資料型(原始型),是 表示最基本資料類型的型別,是所有變數與資料結構的基礎。了解這些型別並適當選擇,可實現 程式的效能提升與記憶體管理的最佳化。 C 語主要有以下 3 種基本資料型
資料型別說明使用範例
整數型(Integer)處理整數的型別int, short, long
浮點型(Floating Point)處理小數的型別float, double
字元型(Character)處理單一字元的型別char
接下來將詳細說明各個資料型別。

1. 整數型(Integer)

整數型是 用於儲存整數的資料型別,也是程式中最常使用的型別之一。

整數型的種類與記憶體大小

整數型有 有號(signed)無號(unsigned) 之分。
資料型別記憶體大小(標準)可儲存值的範圍(32 位元環境)
int4 位元組(32 位元)-2,147,483,648 ~ 2,147,483,647
short2 位元組(16 位元)-32,768 ~ 32,767
long4~8 位元組依環境而定(範圍比 int 更廣)
unsigned int4 位元組0 ~ 4,294,967,295

整數型的使用範例

#include <stdio.h>

int main() {
    int num = 100;         // 一般的整數型
    short smallNum = 10;   // 小型整數(節省記憶體)
    long bigNum = 1000000; // 大的整數
    unsigned int positiveOnly = 300; // 只允許正整數

    printf("num: %d, shortNum: %d, bigNum: %ld, positiveOnly: %un", num, shortNum, bigNum, positiveOnly);
    return 0;
}

2. 浮點型(Floating Point)

浮點型是 處理小數的資料型別。與整數型不同,能精確表示小數。

浮點型的種類

資料型別記憶體大小精度(有效位數)
float4 位元組約6~7位
double8 位元組約15位
long double10~16 位元組約18位以上

浮點型的使用範例

#include <stdio.h>

int main() {
    float pi = 3.14f;         // 加上 "f" 則為 float 型別
    double precisePi = 3.1415926535;  // 更高精度的 double 型別

    printf("pi (float): %.7fn", pi);
    printf("precisePi (double): %.15lfn", precisePi);
    return 0;
}

3. 字元型(Character)

字元型(char)是 用於儲存單一字元的資料型別,實際上會被當作 整數(ASCII 碼) 處理。

字元型的特徵

  • 使用 1 位元組(8 位元)的記憶體
  • char 型使用 ASCII 碼,內部以整數方式處理

字元型的使用範例

#include <stdio.h>

int main() {
    char letter = 'A';  // 儲存字元
    printf("letter: %c", letter);
    printf("ASCII碼: %d", letter);  // 'A' 為 65

    return 0;
}

適當選擇基本資料型

使用哪種基本資料型,取決於 程式的目的與記憶體限制
使用情境建議資料型別原因
迴圈計數器unsigned int不需要負數且效率較佳
小數計算double比 float 精度更高
記憶體節省short / char以最小必要大小管理
處理字串的單一字元char可用 1 位元組管理
short smallNum = 32767;  // 節省記憶體

總結

  • 基本資料型是 C 語程式的基礎,用於處理整數、小數與字元
  • 整數型(int, short, long)處理整數,亦可使用無號(unsigned
  • 浮點型(float, double)處理小數,依精度選擇使用
  • 字元型(char)處理單一字元,內部以整數儲存
  • 適當選擇資料型別可提升程式效能,並節省記憶體

5. 派生資料型(Derived Data Types)

什麼是派生資料型?

C 語的派生資料型(Derived Data Types)是指將基本資料型結合以建立更複雜資料結構的型別。它用於簡潔地處理僅靠基本資料型難以表達的資料結構。 以下是常見的派生資料型。
資料型說明
陣列(Array)儲存多個相同型別的資料
結構體(struct將不同型別的資料作為一個單位管理
共用體(union共享記憶體的資料結構
列舉型(enum定義有意義的常數
指標(Pointer)儲存記憶體位址

1. 陣列(Array)

陣列是指將相同型別的資料儲存在連續的記憶體區域中的資料結構

陣列的宣告與初始化

資料型 陣列名[元素數];
範例(整數型陣列)
int numbers[5] = {10, 20, 30, 40, 50};
陣列元素的存取
printf("%dn", numbers[0]);  // 輸出 10
numbers[1] = 25;  // 更新第2個元素

多維陣列(2D 陣列)

int matrix[2][3] = {
    {1, 2, 3},
    {4, 5, 6}
};
用途: 資料的批次管理、矩陣運算、緩衝區管理等

2. 結構體(struct

結構體是指能將不同型別的資料作為一個單位管理的資料型別

結構體的定義與使用

struct Person {
    char name[50];
    int age;
    float height;
};

int main() {
    struct Person person1 = {"Taro", 25, 175.5};
    printf("Name: %s, Age: %d, Height: %.1f cmn", person1.name, person1.age, person1.height);
    return 0;
}
用途: 學生資料、商品資訊、遊戲角色資訊等

3. 共用體(union

共用體是指共享記憶體的特殊資料型別,且可以以不同型別使用相同的記憶體區域

共用體的定義與使用

union Data {
    int i;
    float f;
};

int main() {
    union Data data;
    data.i = 10;
    printf("Integer: %dn", data.i);

    data.f = 3.14;
    printf("Float: %.2fn", data.f);  // 此時 data.i 的值不確定

    return 0;
}
用途: 需要記憶體節省的情況(例如,以單一變數管理不同資料格式)

4. 列舉型(enum

列舉型是指用於定義有意義常數的資料型別

列舉型的定義與使用

enum Color { RED, GREEN, BLUE };

int main() {
    enum Color favoriteColor = GREEN;
    printf("Favorite Color: %dn", favoriteColor); // 1(GREEN 預設從 0 開始依序編號)
    return 0;
}
用途: 狀態管理(例如:紅綠燈的顏色、星期、遊戲狀態)

5. 指標(Pointer)

指標是指儲存變數位址的特殊資料型別

指標的基本

int a = 10;
int *ptr = &a;  // 將 'a' 的位址儲存於指標

printf("Address of a: %pn", &a);
printf("Pointer Value: %pn", ptr);
printf("Dereferenced Value: %dn", *ptr); // 10

指標的用途

動態記憶體管理(malloc / free函式的陣列傳遞字串操作(char *str

總結

  • 陣列 用於將相同型別的資料集中管理
  • 結構體 用於將不同型別的資料作為一個單位處理
  • 共用體共享記憶體的特殊資料型別
  • 列舉型 用於定義有意義的常數
  • 指標 用於處理變數的位址

6. 型別修飾子(Type Modifiers)

型修飾子是什麼?

C 語言的型修飾子(Type Modifiers) 是用來修改基本資料型別特性的關鍵字。 適當使用型修飾子,可實現記憶體最佳化、資料安全性、處理速度提升等。 C 語言的主要型修飾子如下。
型修飾子說明
const變數的值無法更改(常數)
volatile防止最佳化,讓變數的值每次都從記憶體取得
restrict提升指標的最佳化
signed包含負值的整數型(預設)
unsigned只處理正值的整數型

1. const(宣告常數)

const 修飾子,變數的值將無法被更改。 這有助於防止錯誤的賦值,提升程式碼的安全性

const 的使用範例

#include <stdio.h>

int main() {
    const int MAX_USERS = 100;  // 宣告為常數
    printf("Max Users: %dn", MAX_USERS);

    // MAX_USERS = 200;  // 錯誤!因為 const 無法更改值

    return 0;
}

const 套用於函式參數

void printMessage(const char *message) {
    printf("%sn", message);
    // message[0] = 'H';  // 錯誤!因為 const 無法修改
}
效果: 使用 const 可防止函式內的資料被更改

2. volatile(防止最佳化)

volatile 用於防止編譯器的最佳化。 主要在硬體暫存器、全域變數、割中斷處理中使用。

volatile 的使用範例

#include <stdio.h>

volatile int flag = 0;  // 防止最佳化

int main() {
    while (flag == 0) {
        // 某些處理(迴圈直到 flag 被更改)
    }
    printf("Flag changed!n");
    return 0;
}
用途:
  • 在多執行緒處理中偵測變數的變更
  • 讀取硬體暫存器
  • 監視在割中斷處理中被更改的變數

3. restrict(指標最佳化)

restrict 是自 C99 起引入的修飾子,保證一個指標指向的記憶體區域不會與其他指標共享。 因此可提升最佳化,讓處理速度加快

restrict 的使用範例

#include <stdio.h>

void add_arrays(int *restrict a, int *restrict b, int *restrict result, int size) {
    for (int i = 0; i < size; i++) {
        result[i] = a[i] + b[i];
    }
}
用途:
  • 指標運算的最佳化
  • 數值計算的效能提升
  • 向量運算(SIMD 最佳化)

4. signedunsigned(有號與無號整數)

C 語言的整數型別有兩種:有號(signed)無號(unsigned)
修飾子說明
signed包含負值的整數(預設)
unsigned僅正整數(0 以上)

signed(有號整數)的使用範例

int a = -10;  // 可儲存負值
printf("%dn", a);  // 輸出 -10

unsigned(無號整數)的使用範例

unsigned int b = 250;
printf("%un", b);  // 輸出 250

unsigned int c = -10;  // 錯誤!負值無法儲存
用途:
  • 不使用負值的計數器(迴圈變數等)
  • 二進位資料處理(位元運算)
  • 有效利用記憶體大小
注意: 使用 unsigned 時無法賦予負值,需留意意外的溢位。
int x = -1;
unsigned int y = x;  // 錯誤或產生意外結果

總結

型修飾子用途優點
const宣告不可變更的變數防止錯誤的更改
volatile防止最佳化正確取得割中斷處理與硬體暫存器的值
restrict指標最佳化防止記憶體競爭,實現高速處理
signed包含負值的整數型在處理負數計算時有效
unsigned只處理正值的整數型節省記憶體,適用於計數器與位元運算

7. 型變換(轉型)

什麼是型變換?

C語言中,當在不同資料型別之間執行運算或賦值時,會產生型變換(Type Conversion)。 型變換分為隱式型變換(自動型變換)顯式型變換(轉型)兩種。 如果不正確理解型變換,可能會導致資料精度遺失或產生非預期的錯誤,因此正確區分使用非常重要。

1. 隱式型變換(自動型變換)

在 C 語言中,當對不同資料型別進行運算或賦值時,編譯器會自動執行型變換。 這稱為隱式型變換(Implicit Type Conversion)

隱式型變換的規則

  • 小型資料型別 → 大型資料型別 會自動轉換
  • 整數型 → 浮點型 會被轉換
  • charint(作為 ASCII 碼處理)

隱式型變換的範例

#include <stdio.h>

int main() {
    int a = 10;
    float b = a;  // int → float 自動轉換
    printf("b: %.2fn", b);  // 輸出: b: 10.00

    char letter = 'A';
    int asciiValue = letter;  // char → int 轉換(ASCII 碼)
    printf("ASCII value of A: %dn", asciiValue);  // 輸出: ASCII value of A: 65

    return 0;
}

2. 顯式型變換(轉型)

顯式型變換(Explicit Type Conversion) 中,開發者會有意地轉換資料型別。 此轉換稱為轉型(Casting)

轉型的基本語法

(轉換後的資料型別) 值或變數

轉型的使用範例

#include <stdio.h>

int main() {
    int a = 10, b = 3;
    float result = (float)a / b;  // int 轉換為 float
    printf("Result: %.2fn", result);  // 輸出: Result: 3.33

    return 0;
}
a 透過 (float) 轉型,可防止整數相除時的截斷

3. 需要轉型的情況

(1) 整數相除

int a = 5, b = 2;
float result = a / b;  // 結果為 2(仍為整數)
float correctResult = (float)a / b;  // 正確得到 2.5
要點: 只要將其中一個轉為 float,結果也會是 float

(2) 浮點 → 整數(小數部分截斷)

float pi = 3.14159;
int truncatedPi = (int)pi;  // 變成 3(小數部分被截斷)
注意: 轉型後小數點以下會被截斷!

(3) charint(將字元轉為 ASCII 碼)

char letter = 'B';
int ascii = (int)letter;
printf("ASCII Code: %dn", ascii);  // 輸出: ASCII Code: 66
char 型在內部被視為整數(ASCII 碼)

(4) 從 void * 轉型(指標)

指標可以使用 void * 型以通用方式處理,但若不將其轉為適當的型別,會導致誤動作。
void *ptr;
int num = 10;
ptr = &num;

int *intPtr = (int *)ptr;  // 從 void * 轉型為 int *
printf("Value: %dn", *intPtr);  // 輸出: Value: 10

4. 型變換的注意事項

(1) 資料精度遺失

在執行型變換時,可能會遺失資料精度
float num = 3.9;
int rounded = (int)num;  // 結果: 3(小數點以下被截斷)
解決方案: 若要四捨五入,請使用 round()
#include <math.h>
int rounded = round(num);  // 變成 4

(2) 注意 unsignedsigned 的轉換

unsigned int x = -1;
printf("%un", x);  // 輸出: 4294967295(32 位元環境)
將負值賦給無號型(unsigned)會產生非預期的結果!

(3) 從較大型別轉為較小型別(溢位風險)

long bigNum = 100000;
short smallNum = (short)bigNum;  // 可能無法正確儲存資料
解決方案: 事先使用 sizeof() 確認資料大小
printf("Size of short: %lu bytesn", sizeof(short));

總結

型變換的種類說明範例
隱式型變換編譯器自動轉換型別int → float
顯式型變換(轉型)開發者有意轉換型別(float)a / b
整數相除int / int 時小數會被截斷(float)5 / 2 → 2.5
浮點 → 整數小數部分會被截斷(int)3.9 → 3
指標的轉型void * 轉為適當的型別(int *)ptr
適當運用型變換,您可以撰寫安全且錯誤較少的程式

8. 變數的範圍與壽命

變數的範圍(有效範圍)是什麼?

在 C 語言中、變數的範圍(Scope) 指的是,「該變數可以從哪裡被參照(有效範圍)」。 範圍會影響程式的設計,如果未適當管理,會成為意外行為或錯誤的原因

C 語言的變數範圍類型

範圍類型說明有效範圍
區域變數僅能在函式內使用在宣告的函式或區塊內
全域變數在整個程式中皆可使用整個程式
區塊範圍{} 內僅有效在宣告的區塊內
檔案範圍無法從其他檔案存取在定義的檔案內

1. 區域變數(Local Variables)

區域變數 是在函式或區塊 {} 內部宣告,且 僅在函式內有效

區域變數的使用範例

#include <stdio.h>

void myFunction() {
    int localVar = 10;  // 區域變數
    printf("Local variable: %dn", localVar);
}

int main() {
    myFunction();
    // printf("%d", localVar);  // 錯誤!區域變數無法從函式外存取
    return 0;
}
優點:
  • 可防止函式間的影響(安全性高)
  • 節省記憶體(函式結束時自動釋放)
注意事項:
  • 無法從函式外存取
  • 每次呼叫函式時都會重新初始化(資料不會保留)

2. 全域變數(Global Variables)

全域變數 是在函式外宣告,且 在整個程式中皆可存取

全域變數的使用範例

#include <stdio.h>

int globalVar = 100;  // 全域變數

void myFunction() {
    printf("Global variable: %dn", globalVar);
}

int main() {
    myFunction();
    globalVar = 200;  // 可從任何地方修改
    printf("Updated global variable: %dn", globalVar);
    return 0;
}
優點:
  • 可在整個程式中保留值
  • 可在多個函式間共享資料
缺點:
  • 可能發生意外的修改(錯誤的原因)
  • 持續佔用記憶體
  • 不易模組化
👉 解決方案: 使用 static 來限制全域變數(在下一節說明)

3. 靜態變數(Static Variables)

加上 static即使是區域變數也能持續保留值。此外,對全域變數加上 static,則僅在該檔案內有效

static 的使用範例(保留區域變數)

#include <stdio.h>

void counter() {
    static int count = 0;  // static 保持值
    count++;
    printf("Count: %dn", count);
}

int main() {
    counter();  // 輸出: Count: 1
    counter();  // 輸出: Count: 2
    counter();  // 輸出: Count: 3
    return 0;
}
優點:
  • 每次呼叫函式時都保留值
  • 記憶體管理簡單
缺點:
  • 直到程式結束才釋放記憶體

static 的使用範例(限制全域變數)

static int fileVar = 100;  // 僅在此檔案內有效
更易模組化,安全性提升

4. 外部變數(Extern)

使用 extern 關鍵字,可參照其他檔案中的變數。

extern 的使用範例

file1.c
#include <stdio.h>

int sharedVar = 50;  // 全域變數

void printSharedVar() {
    printf("Shared Variable: %dn", sharedVar);
}
file2.c
#include <stdio.h>

extern int sharedVar;  // 參照 file1.c 的變數

int main() {
    printf("Accessing sharedVar: %dn", sharedVar);
    return 0;
}
優點:
  • 可利用其他檔案的變數
缺點:
  • 依賴關係變強,導致維護性下降

5. 變數的壽命(Lifetime)

變數的壽命(Lifetime)指的是 變數在記憶體上存在的期間
變數類型壽命(Lifetime)釋放時機
區域變數函式執行期間函式結束時
全域變數整個程式程式結束時
靜態變數 (static)整個程式程式結束時
動態記憶體配置 (malloc)free() 直到呼叫free() 直到呼叫

總結

變數類型範圍(有效範圍)壽命(Lifetime)
區域變數僅在函式內直到函式結束
全域變數整個程式程式結束時
靜態變數 (static)在宣告的範圍內程式結束時
外部變數 (extern)可從其他檔案參照在宣告的範圍內
透過適當管理變數的範圍與壽命,可防止記憶體浪費,並製作較少錯誤的程式

9. 實務資料型的選擇方法

資料型選擇重要的原因

C 語言中,透過適當選擇資料型別,可實現記憶體最佳化、確保計算精度、提升效能 等好處。 若選擇不適當的資料型別,可能會產生 記憶體浪費、溢位、資料遺失 等問題。

1. 想要節省記憶體時

在嵌入式系統或受記憶體限制的環境中,盡可能選擇 較小的資料型別 是很重要的。

整數的記憶體大小與選擇方式

資料型別記憶體大小範圍(32 位元環境)
char1 位元組-128 ~ 127
short2 位元組-32,768 ~ 32,767
int4 位元組-2,147,483,648 ~ 2,147,483,647
long4~8 位元組int 更廣的範圍
unsigned int4 位元組0 ~ 4,294,967,295

記憶體節省的範例

short temperature;  // 為了節省記憶體而使用 short
適用情境: 感測器資料、迴圈計數器、處理小範圍值的變數 ⚠ 注意: 超出範圍會有溢位的危險!

2. 需要精度時

在計算精度重要的情況下,使用 double 可以 防止捨入誤差

浮點數的選擇方式

資料型別記憶體大小有效位數
float4 位元組約 6~7 位
double8 位元組約 15 位
long double10~16 位元組約 18 位以上

確保精度的範例

double distance = 1234567.1234567;  // 需要高精度計算的情況
適用情境: 科學計算、金融計算、測量資料 ⚠ 注意: 由於 float 誤差較大,在需要精度的情況下應使用 double

3. 不處理負值時

使用 unsigned 可以 擴大正值範圍並提升記憶體效率

不處理負值的範例

unsigned int score = 250;
適用情境: 計數器、大小指定、位元運算 ⚠ 注意: 使用 unsigned 後無法賦予負值,需留意意外的溢位。
int x = -1;
unsigned int y = x;  // 會產生錯誤或非預期結果

4. 適合迴圈計數器的資料型別

迴圈計數器使用 int 之上,unsigned int 更為適合。
for (unsigned int i = 0; i < 1000; i++) {
    // 迴圈處理
}
優點: 由於 unsigned 不考慮負值,處理較易最佳化。

5. 處理文字時

char 只能 儲存單一字元,但若處理字串則需使用 char 陣列。
char letter = 'A';   // 只能單一字元
char str[] = "Hello";  // 字串
適用情境: 單一字元處理(char)、字串處理(char 陣列)

6. 使用列舉型讓程式碼更易懂

若想以 有意義的名稱管理整數值,使用 enum 可提升可讀性。
enum Color { RED, GREEN, BLUE };

enum Color favoriteColor = GREEN;
適用情境: 狀態管理(例如:信號顏色、星期、遊戲狀態)

7. 使用指標靈活管理記憶體

若要靈活管理資料的存放位置,會 使用指標
int num = 10;
int *ptr = &ampnum
printf("Value: %dn", *ptr);  // 10
適用情境: 動態記憶體管理、大量資料處理

8. 最佳資料型的選擇方式(總結)

使用情境建議資料型別原因
迴圈計數器unsigned int不需要負數且易於最佳化
小整數short節省記憶體
高精度計算doublefloat 誤差少
無號資料unsigned int可擴大範圍
字元處理char儲存單一字元資料
狀態管理enum易讀且減少錯誤
彈性資料管理pointer記憶體管理更容易
✅ 重點總結
  • 需要節省記憶體時使用 shortchar
  • 需要精度時選擇 double
  • 若不需要負值則活用 unsigned
  • 為提升可讀性活用 enum
  • 活用指標即可實現彈性記憶體管理
選擇適當的資料型別,可使 程式的最佳化與安全性提升 成為可能。

10. 總結

C語言中變數與資料型別的重要性

在 C 語言中,變數與資料型別的理解是程式設計的基礎。 選擇適當的資料型別,記憶體最佳化、處理速度提升、避免錯誤 成為可能。 本文將詳細說明以下重點。

1. 什麼是變數?

  • 變數是儲存資料的箱子,用於在程式中保持可變的值。
  • 需要宣告與初始化變數,且選擇適當的資料型別很重要。
int age = 25;  // 整數型變數
float pi = 3.14;  // 小數型變數
char letter = 'A';  // 字元型變數

2. C語言的資料型別概述

  • 基本資料型別(整數型・浮點型・字元型)
  • 衍生資料型別(陣列・結構體・共用體・列舉型・指標)
  • 透過選擇適當的資料型別,可防止記憶體浪費,提升程式效率

3. 基本資料型別(原始型別)

資料型別記憶體大小特徵
int4位元組整數
float4位元組可處理小數但精度較低
double8位元組高精度小數
char1位元組儲存1個字元

4. 衍生資料型別(陣列・結構體・共用體・列舉型・指標)

  • 陣列(Array) → 儲存多個相同型別的資料
  • 結構體(struct → 將不同型別的資料作為一個單位管理
  • 共用體(union → 共享記憶體的特殊資料型別
  • 列舉型(enum → 定義有意義的常數
  • 指標(Pointer) → 儲存記憶體位址,實現彈性資料管理

5. 型別修飾子

使用型別修飾子可以變更資料型別的特性。
修飾子說明
const常數(值不可變更)
volatile防止最佳化(用於硬體處理)
restrict指標的最佳化
unsigned僅正值
const int MAX_USERS = 100;  // 值不可變更

6. 型別轉換(轉型)

當需要在不同資料型別之間轉換時,隱式型別轉換(自動)與顯式型別轉換(轉型) 會發生。
int a = 10;
float b = (float)a / 3;  // 轉型

7. 變數的作用域與生命週期

  • 區域變數 → 僅在函式內有效
  • 全域變數 → 在整個程式中有效(但需注意管理)
  • static → 可保持值,但作用域受限
  • extern → 可從其他檔案參照變數
static int counter = 0;  // 保持值的區域變數

8. 實務上資料型別的選擇方式

使用情境建議資料型別理由
迴圈計數器unsigned int不需要負數且有效率
小整數short節省記憶體
高精度計算doublefloat 比較誤差少
狀態管理enum易讀且減少錯誤
彈性資料管理指標動態記憶體管理適用

9. FAQ(常見問題)

Q1. intlong 的差異是?

A: long 能儲存比 int 更廣範圍的值。但依環境大小可能不同。
long num = 1000000;

Q2. floatdouble 該使用哪一個?

A: 需要高精度時使用 double,需要節省記憶體時使用 float
double distance = 3.1415926535;

Q3. 使用 unsigned 有何不同?

A: unsigned 不處理負值,能儲存更大的正值
unsigned int positive = 250;

Q4. char 型也能作為數值使用嗎?

A: 可作為 ASCII 碼進行整數運算
char letter = 'A';
int ascii = (int)letter;  // 65

Q5. 使用 const 的好處是?

A: 防止誤改值,提高安全性。
const int MAX_VALUE = 100;

總結

  • 在 C 語言中,適當的資料型別選擇能提升程式品質
  • 善用型別修飾子與轉型,可撰寫安全且高效的程式
  • 了解作用域與生命週期,即可適當管理變數
  • 掌握實務上資料型別的選擇,可進行更佳的程式設計
熟練運用 C 語言的資料型別,目標是撰寫高效且錯誤少的程式!