在學習 C 語言時,理解其基本語法結構是非常重要的一步。以下這段範例程式碼提供了清楚的入門示範,其中包含了資料型態、輸出格式控制符號(format specifier)、ASCII 編碼的運用、與型別所占記憶體大小的基本介紹。
讓我們從一個經典的 "Hello, World!"
程式開始,解析其組成:
#include<stdio.h>
int main() {
printf("Hello, World!");
return 0;
}
#include<stdio.h>
:引入標準函式庫
#include
是一個前置處理器指令 (Preprocessor Directive)。前置處理器是 C 編譯過程的第一個階段,它會在實際編譯原始碼之前處理這些指令。
<stdio.h>
:這是 C 語言的標準輸入輸出標頭檔 (Standard Input/Output Header File)。它包含了我們常用函式的宣告,例如 printf()
(用於螢幕輸出) 和 scanf()
(用於鍵盤輸入)。
為何需要引入? C 語言本身的核心功能非常精簡。許多常用的功能,如螢幕印出文字、讀取使用者輸入等,都是以函式庫的形式提供的。#include <stdio.h>
的作用就像是告訴編譯器:「我接下來的程式碼中,可能會用到 stdio.h
裡面定義好的功能,請幫我把這些功能的宣告資訊準備好。」如果沒有引入這個標頭檔,編譯器在遇到 printf()
這類函式時,就會因為找不到其定義而產生錯誤。
int main() { ... }
:程式的入口——主函式
在 C 語言中,main()
函式是一個非常特殊的存在,它是程式執行的起點。作業系統在執行您的 C 程式時,會首先尋找並呼叫這個 main()
函式。
int
:這是 main()
函式的回傳型態 (Return Type),代表 main()
函式執行完畢後,會回傳一個整數值給作業系統。這個回傳值通常用來表示程式是否正常結束。依照慣例,回傳 0 代表程式執行成功,非零值則代表發生了某些錯誤。
main
:這是函式的名稱,固定寫為 main。
()
:函式名稱後面的括號是用來放置參數 (Parameters) 的地方。在這個範例中,main()
函式沒有接收任何參數,所以括號是空的。
{ ... }
:大括號定義了函式主體 (Function Body) 的範圍,也就是 main()
函式實際執行的程式碼都寫在這對大括號之間。
標準 C 語言規範中,int main()
是最被推薦且廣泛接受的寫法。有些舊的或非標準的編譯器可能允許 void main()
,表示 main
函式不回傳任何值。然而,這並不符合 C 語言標準,可能會導致在某些編譯器或作業系統上出現警告或非預期的行為。因此,強烈建議始終使用 int main()
。
main
函式也可以接收參數,常見的寫法是 int main(int argc, char *argv[])
,這允許程式在執行時從命令列接收參數,但這是更進階的主題。
printf("Hello, World!");
:在螢幕上顯示訊息
printf()
是 stdio.h
中定義的一個函式,其名稱是 "print formatted"
的縮寫,意思是「格式化輸出」。
"Hello, World!"
:這是一個字串字面量 (String Literal),也就是您想要在螢幕上顯示的文字內容。在 C 語言中,字串必須用雙引號 "
包起來。
;
(分號):在 C 語言中,分號代表一個陳述 (Statement) 的結束。大部分的 C 語言程式碼行都需要以分號結尾。
return 0;
:程式的結束與回傳值
這行程式碼代表 main()
函式執行結束,並回傳一個值 0 給作業系統。return
:這是一個關鍵字,用於結束目前函式的執行,並將一個值回傳給呼叫者。在 main() 函式中,呼叫者就是作業系統。0
:這是回傳給作業系統的整數值。如前所述,0 通常表示程式成功執行。
現在,我們來看一段更複雜的程式碼,它展示了 C 語言中不同的資料型態以及 printf 函式的更多用法:
#include<stdio.h>
int main() {
int age = 35; // 整數變數
printf("年齡是:%d\n", age);
printf("age 變數的大小是 %d 位元組 (bytes)。\n", sizeof(age));
float salary = 56.5; // 浮點數變數
printf("薪水是:%.1f\n", salary);
//這表示輸出浮點數時,只顯示到小數點後第一位。. 後面的數字指定了小數點後的位數。
char unit = 'A'; // 字元變數
printf("unit 字元的十進制 ASCII 碼是:%d\n", unit);
unit = 98; // 賦予字元變數新的 ASCII 值
printf("ASCII 碼 98 對應的字元是:%c\n", unit);
printf("這是一段直接輸出的文字:abcdef\n");
return 0;
}
int age = 35;
int
:這是整數 (Integer) 資料型態,用於儲存沒有小數點的數字,例如 -1, 0, 100。age
:這是我們宣告的變數名稱。=
:這是賦值運算子 (Assignment Operator),用於將右邊的值存入左邊的變數中。35
:這是賦予給 age 變數的初始值。printf
("年齡是:%d\n", age);
%d
:這是 printf
函式中的格式控制符號 (Format Specifier),用於指示 printf
在這個位置輸出一 個十進制整數。printf
會取用逗號後面的第一個參數 (此處為 age) 的值,並以整數形式印出。\n
:這是一個跳脫序列 (Escape Sequence),代表換行符 (Newline Character)。它會使游標移到下一行的開頭。printf("age 變數的大小是 %d 位元組 (bytes)。\n", sizeof(age));
sizeof()
:這是一個運算子 (Operator),它會回傳其運算元 (可以是變數或資料型態) 在記憶體中所佔用的空間大小,單位是位元組 (bytes)。int 型態的大小在不同的系統和編譯器上可能不同,但通常是 4 個位元組。char unit = 'A';
char
:這是字元 (Character) 資料型態,用於儲存單一字元,例如 'A', 'b', '!', '7'。注意,字元值必須用單引號 ' 包起來。printf("unit 字元的十進制 ASCII 碼是:%d\n", unit);
char
型態的變數時,printf
會印出該字元對應的 ASCII (美國資訊交換標準碼) 值的十進制表示。字元 'A' 的 ASCII 十進制值是 65,所以這行會印出 unit 字元的十進制 ASCII 碼是:65。unit = 98;
這裡我們將整數 98 賦值給 char
型態的變數 unit。C 語言允許這樣做,因為字元在內部實際上是以其 ASCII (或其他字元集) 的數值來儲存的。數字 98 對應的 ASCII 字元是 'b'。
printf("ASCII 碼 98 對應的字元是:%c\n", unit);
%c
:這是用於輸出單一字元的格式控制符號。printf 會將 unit 變數中儲存的數值 (98) 解釋為其對應的 ASCII 字元,並印出該字元。所以這行會印出 ASCII 碼 98 對應的字元是:b。printf
函數的格式控制符號
printf
函式使用格式控制符號來指定輸出的格式。這些符號通常以 % 開頭。
常見的控制符號:
ASCII 為每個常用的英文字母 (大小寫)、數字、標點符號以及一些控制字元 (如換行符、Tab鍵) 都分配了一個唯一的數字,範圍通常是 0 到 127。
char
型態的變數在記憶體中儲存的就是這些數字編碼。
當你寫 char c = 'A';
時,實際上是將 'A' 對應的 ASCII 值 (即 65) 存入了變數 c。
當你使用 printf("%c", c);
時,printf 會查找 c 中儲存的數字 (65) 在 ASCII 表中對應的字元 ('A') 並顯示出來。
當你使用 printf("%d", c);
時,printf 則直接將 c 中儲存的數字 (65) 以十進制整數的形式顯示出來。
每種資料型態都有其特定的屬性:
是否有號 (Signed / Unsigned):
大小 (Size):
指該資料型態在記憶體中所佔用的位元組數。可以使用 sizeof() 運算子來獲取。
數值範圍 (Range):
指該資料型態可以表示的最小和最大數值。範圍取決於其大小和是否有號。
類別 | 資料型態 | 有號/無號 | 記憶體大小 (byte) | 數值範圍 (概略) |
---|---|---|---|---|
整數 | short |
有號 | 2 | -32,768 ~ 32,767 |
整數 | int |
有號 | 4 | -2,147,483,648 ~ 2,147,483,647 |
整數 | long |
有號 | 4 或 8(視系統而定) | 約 -2^31 ~ 2^31-1 或更大 |
整數 | long long |
有號 | 8 | 約 -9.2×10^18 ~ 9.2×10^18 |
整數 | unsigned short |
無號 | 2 | 0 ~ 65,535 |
整數 | unsigned int |
無號 | 4 | 0 ~ 4,294,967,295 |
整數 | unsigned long |
無號 | 4 或 8 | 約 0 ~ 4,294,967,295 或更大 |
整數 | unsigned long long |
無號 | 8 | 約 0 ~ 1.8×10^19 |
字元 | char |
有號/無號 | 1 | -128 ~ 127 / 0 ~ 255 |
浮點數 | float |
有號 | 4 | 約 ±3.4E±38(約 7 位有效數字) |
浮點數 | double |
有號 | 8 | 約 ±1.7E±308(約 15~16 位有效數字) |
在 C 語言中,型別轉換(type casting)是程式設計中一個非常重要的概念,尤其當我們處理不同資料型態之間的轉換時,可能會產生預期內或意料外的結果。以下的範例程式碼展示了各種不同的型別轉換情況,並說明其背後的轉換規則與潛在風險。
#include<stdio.h>
int main() {
int a = 15;
short b = (short)a;
printf("%d\n", b);
short c = 200;
int d = (int)c;
printf("%d\n", d);
int e = 32769;
short f = (short)e;
printf("%d\n", f); // 溢出
int g = -55;
unsigned short h = (unsigned short)g;
printf("%u\n", h); // 溢出
float f_1 = 15.5;
double f_2 = (double)f_1;
printf("%.3f\n", f_2);
double f_3 = 3.5e38;
float f_4 = (float)f_3;
printf("%f\n", f_4);
}
C 語言支援兩種型別轉換:
int
轉為 float
。(目標型別)變數名稱
。例如:(short)a
表示將整數 a
強制轉換成 short
型態。int a = 15;
short b = (short)a;
這裡將 int
轉為 short
,由於值 15 在 short
可表示的範圍內(-32768 ~ 32767),所以轉換後數值保持不變。
short c = 200;
int d = (int)c;
這是小型資料型態轉為大型型別的安全轉換,short
轉成 int
,值仍為 200,這是沒有資訊損失的升階(promotion)。
int e = 32769;
short f = (short)e;
這一行展示了**溢出(overflow)**的情況。32769 超出了 short
所能表示的最大值(32767),因此強制轉型時會導致值「環繞」回負數,結果會是一個看似亂數的負整數(通常為 -32767)。這也說明了型別轉換若發生於超出目標型別表示範圍,將會發生資料損失。
int g = -55;
unsigned short h = (unsigned short)g;
這裡是將負整數轉成無號整數,也是一種典型的溢出情況。因為 unsigned short
不能表示負數,結果會以二進位補數方式解讀,輸出為一個大的正整數,例如 65536 - 55 = 65481
。這是「位元模式不變,但詮釋方式不同」的情形。
float f_1 = 15.5;
double f_2 = (double)f_1;
這是從 float
轉為 double
的情況,由於 double
精度較高,這是一種安全轉型(promotion),原本 float
的值可以完整儲存在 double
中。
double f_3 = 3.5e38;
float f_4 = (float)f_3;
這行使用了科學記號 3.5e38
,等同於 3.5 × 10^38
。這超過了 float
可表現的最大數值(約 3.4 × 10^38),因此發生了溢出或近似誤差,可能顯示為 inf
或近似值,這取決於平台與編譯器的實作。
了解這些規則能幫助我們寫出更安全與可預測的 C 程式。
透過這個範例程式碼,我們學會了 C 語言中變數宣告、資料型態、格式控制符、ASCII 編碼與記憶體大小的基礎概念、型別轉換。掌握這些內容,對未來學習更進階的運算、邏輯控制與函式撰寫有重要幫助。