1 C 語言基本資料型態、記憶體大小與表示範圍
宣告變數就像向作業系統「租用特定大小的置物櫃」。不同型態的置物櫃容量不同,能裝載的數值範圍也完全不同。在標準 32/64 位元電腦架構下:
| 資料型態 | 記憶體大小 | 位元數 (Bits) | 數值表示範圍 | 主要用途與特性 |
|---|---|---|---|---|
char |
1 Byte | 8 bits | -128 ~ 127 | 存放單一字元(ASCII 碼)或超小型整數。 |
unsigned char |
1 Byte | 8 bits | 0 ~ 255 | 無號字元,常用於二進位資料處理。 |
short / short int |
2 Bytes | 16 bits | -32,768 ~ 32,767 (±3.2 萬) | 小型整數(統測 114 年考題:範圍在 ±20000 應選 short)。 |
unsigned short |
2 Bytes | 16 bits | 0 ~ 65,535 (2¹⁶ - 1) | 16 位元無號整數。 |
int |
4 Bytes | 32 bits | -2,147,483,648 ~ 2,147,483,647 (-2³¹ ~ 2³¹ - 1) |
標準整數,最常用的預設計算型態(統測 114 年必考!)。 |
unsigned int |
4 Bytes | 32 bits | 0 ~ 4,294,967,295 (0 ~ 2³² - 1) |
32 位元無號整數,所有位元皆表示數值大小。 |
long long |
8 Bytes | 64 bits | -2⁶³ ~ 2⁶³ - 1 (約 ±9×10¹⁸) | 超大整數,格式化字串使用 %lld。 |
float (單精度浮點數) |
4 Bytes | 32 bits | ±3.4×10⁻³⁸ ~ ±3.4×10³⁸ 有效位數約 6~7 位 |
佔 4 Bytes,精確度較 double 低(統測 111 年考題)。 |
double (雙精度浮點數) |
8 Bytes | 64 bits | ±1.7×10⁻³⁰⁸ ~ ±1.7×10³⁰⁸ 有效位數約 15~17 位 |
佔 8 Bytes,精確度高於 float,預設浮點常數型態。 |
若一個整數型態佔用 n 個位元(bits):
• 無號整數(Unsigned):全部位元皆表示大小,範圍為 0 ~ 2n - 1。
• 有號整數(Signed):最高位元(MSB)作為正負號(0 為正、1 為負),範圍為 -2n-1 ~ 2n-1 - 1。
例如 32 位元:
• int (有號) 最大值為 2³¹ - 1 (2,147,483,647)
• unsigned int (無號) 最大值為 2³² - 1 (4,294,967,295)
2 有號數(Signed)vs 無號數(Unsigned)與二補數表示法
電腦內部一律使用「二進位」儲存資料。對於有號整數,電腦採用「二補數(Two's Complement)」系統來表示負數:
#include <stdio.h>
int main(void) {
signed char sc = -1;
unsigned char uc = 255;
// 二進位中,8 個 bit 全為 1 即 11111111
// 若視為 signed char,以二補數解讀代表 -1
// 若視為 unsigned char,以無號數解讀代表 255
printf("有號數 sc = %d, 無號數 uc = %u\n", sc, uc);
return 0;
}
3 整數溢位(Integer Overflow)與時鐘環繞機制
當運算結果超出了該型態所能承載的最大值時,就會發生「溢位(Overflow)」。在二補數系統中,數值會像時鐘指針走過 12 點一樣,瞬間環繞回最小值!
#include <stdio.h>
int main(void) {
short s = 32767; // short 為 16 位元有號整數,最大值為 32767 (01111111 11111111)
s = s + 1; // +1 後二進位變成 10000000 00000000(最高位元變成 1,代表負數最小值)
printf("s + 1 = %d\n", s); // 輸出 -32768!
unsigned short us = 65535; // 無號 short 最大值
us = us + 1; // +1 溢位環繞回 0
printf("us + 1 = %u\n", us); // 輸出 0!
return 0;
}
us + 1 = 0
整數溢位屬於邏輯運算錯誤,編譯器在編譯階段不會報錯(Syntax error),程式也能正常執行,但算出來的數據會變成面目全非的負數或 0!
4 char 的本質是 1 位元組整數與 ASCII 碼運算
在 C 語言中,字元變數 char 實際上存放的是該字元在 ASCII 編碼表中的整數編號。因此,字元可以與整數直接進行加減運算!
| 字元常數 | ASCII 碼 (十進位) | ASCII 碼 (十六進位) | 高職統測必背常考特性 |
|---|---|---|---|
'0' |
48 | 0x30 | 數字字元 '0'~'9'('0'=48, '1'=49 ... '9'=57) |
'A' |
65 | 0x41 | 大寫字母 'A'~'Z'('A'=65, 'B'=66 ... 'Z'=90) |
'a' |
97 | 0x61 | 小寫字母 'a'~'z'('a'=97, 'b'=98 ... 'z'=122) |
'\0' (Null) |
0 | 0x00 | 字串結束符號(數值恰為 0) |
#include <stdio.h>
int main(void) {
char ch = 'A';
printf("字元: %c, ASCII碼: %d\n", ch, ch); // 印出 'A' 與 65
// 下一個字元:'A' + 1 = 66 = 'B'
char next_ch = ch + 1;
printf("下一個字元: %c\n", next_ch); // 印出 'B'
// 大寫轉小寫:'a' - 'A' = 97 - 65 = 32
char lower_ch = ch + 32;
printf("轉小寫: %c\n", lower_ch); // 印出 'a'
// 數字字元轉整數:'7' - '0' = 55 - 48 = 7
char num_char = '7';
int real_num = num_char - '0';
printf("數字字元轉數值: %d\n", real_num); // 印出 7
return 0;
}
下一個字元: B
轉小寫: a
數字字元轉數值: 7
5 sizeof() 運算子與指標大小超經典陷阱
sizeof 不是函式,而是 C 語言的單元運算子(Compile-time Operator)。它在編譯階段直接計算出某型態或變數在記憶體中佔用的 Bytes(位元組數)。
• sizeof(指標變數):計算的是「指標(記憶體位址)本身」的大小!在 64 位元系統上,任何型態的指標(int*, char*, double*)都是 8 Bytes(在 32 位元系統為 4 Bytes)。
• sizeof(*指標變數):前面加了星號 * 代表取值(Dereference),計算的是「指標所指向的資料型態」大小!例如 char *s,則 sizeof(*s) 是 sizeof(char) = 1 Byte!
#include <stdio.h>
int main(void) {
char *str = "ABCDEF";
int *iptr;
double *dptr;
// 64 位元系統上,所有指標本身都是 8 位元組
printf("sizeof(str) = %zu bytes (指標本身大小)\n", sizeof(str)); // 8
printf("sizeof(iptr) = %zu bytes (指標本身大小)\n", sizeof(iptr)); // 8
printf("sizeof(dptr) = %zu bytes (指標本身大小)\n", sizeof(dptr)); // 8
// 取值後的大小:
printf("sizeof(*str) = %zu bytes (char 型態大小)\n", sizeof(*str)); // 1
printf("sizeof(*iptr) = %zu bytes (int 型態大小)\n", sizeof(*iptr)); // 4
printf("sizeof(*dptr) = %zu bytes (double 型態大小)\n", sizeof(*dptr)); // 8
return 0;
}
sizeof(iptr) = 8 bytes (指標本身大小)
sizeof(dptr) = 8 bytes (指標本身大小)
sizeof(*str) = 1 bytes (char 型態大小)
sizeof(*iptr) = 4 bytes (int 型態大小)
sizeof(*dptr) = 8 bytes (double 型態大小)
6 整數除法(Integer Division)vs 浮點數除法(統測每屆必考!)
這是高職統測最常出現的第一大失分陷阱:「兩個整數相除,結果必定是整數,小數點直接無條件捨去(Truncated towards zero)!」
| 運算式寫法 | 運算元型態 | 計算過程 | 最終結果 | 說明 |
|---|---|---|---|---|
7 / 2 |
int / int |
7 ÷ 2 = 3.5 → 捨去小數 | 3 | 整數除法,小數直接丟失! |
7.0 / 2 |
double / int |
7.0 ÷ 2.0 = 3.5 | 3.5 | 只要其中一方有浮點數,就升級為浮點除法。 |
(float)7 / 2 |
float / int |
7.0f ÷ 2.0f = 3.5 | 3.5 | 強制轉型先執行,正確拿到小數點。 |
(float)(7 / 2) |
(float)(int) |
先算括號內 7/2=3,再轉 float | 3.0 | ❌ 陷阱!括號內早已被截斷為 3! |
#include <stdio.h>
int main(void) {
int a = 7, b = 2;
int x = a / b; // 7 / 2 = 3 (整數除法)
float y = (float)a / b; // 先把 a 轉為 7.0f,7.0f / 2 = 3.5f (浮點數除法)
float z = (float)(a / b); // 括號先算 a/b=3,(float)3 = 3.0f (陷阱!)
printf("x = %d\n", x); // 3
printf("y = %f\n", y); // 3.500000
printf("z = %f\n", z); // 3.000000
return 0;
}
y = 3.500000
z = 3.000000
7 型態轉換機制:隱性型態提升(Implicit Promotion)vs 強制轉型(Explicit Cast)
當不同型態的資料在一起運算時,C 語言會自動進行「隱性型態提升(自動轉型)」,遵循「小容量型態自動升級為大容量型態」的原則:
在進行任何算術運算前,會自動提升(Integral Promotion)為 int。
若與 long 或浮點數運算,會進一步升級為更大範圍的型態。
若運算式中出現 double,float 會自動轉為 double 運算。
精度最高的等級,整個運算式的結果最終以 double 計算。
8 格式化輸出規格符與進位制換算 (%d, %o, %x)
printf() 透過不同的格式指定字(Format Specifier),可以將同一個二進位數值輸出為不同的進位制與外觀:
| 指定字 | 進位制 / 格式 | 範例輸入 (數值 34) | 輸出結果 | 說明 |
|---|---|---|---|---|
%d / %i |
十進位有號整數 (Decimal) | 34 | 34 |
標準十進位整數 |
%u |
十進位無號整數 (Unsigned) | 34 | 34 |
以無號數格式輸出 |
%o |
八進位整數 (Octal) | 34 = 4×8¹ + 2×8⁰ | 42 |
八進位輸出(統測 114 年考題 Q43!) |
%x / %X |
十六進位整數 (Hexadecimal) | 138 = 8×16¹ + 10×16⁰ | 8a / 8A |
十六進位輸出(10 為 a/A) |
%f / %lf |
浮點數 (預設 6 位小數) | 8.625 | 8.625000 |
float / double 格式輸出 |
%6.4f |
總寬度 6 格、小數點後 4 位 | 8.625 | 8.6250 |
小數點後精確到 4 位(統測 114 年考題) |
9 111~115 歷屆統測真題全選項深度剖析(共 7 題)
以下收錄統測專業科目(二)近年全部 7 題資料型態與轉型真題。每題均提供高解析度原始考題掃描圖、互動選項按鈕與所有選項逐項深入解析:
🔍 四個選項逐項深度剖析
float 是單精度浮點數(Single Precision),佔 4 Bytes (32 bits),有效數字約 6~7 位;而 double 是雙精度浮點數(Double Precision),佔 8 Bytes (64 bits),有效數字高達 15~17 位。兩者的佔用空間與精確度截然不同,double 精確度遠高於 float。故 (A) 敘述錯誤,為本題所選。
int 是 integer 的縮寫,為 C 語言用來儲存整數的標準基本資料型態。本敘述正確。
double 專門用來儲存高精度的倍精準度浮點數(小數)。本敘述正確。
char 是 character 的縮寫,佔 1 Byte,專門用來儲存 ASCII 字元符號(如 'A'、'9')。本敘述正確。
int x, a=7, b=2;
float y;
x=a/b;
y=(float)a/b;
🔍 逐步追蹤與原理剖析
x = a / b;:a 與 b 都是 int 整數,兩整數相除進行整數除法,7 / 2 = 3.5 捨去小數點後得到整數 3,存入整數變數 x,故 x = 3。2.
y = (float)a / b;:強制轉型運算子 (float) 的優先順序高於除法 /,因此先將 a 轉成浮點數 7.0f;接著 7.0f / 2 為浮點數除法,得到 3.5f 存入 y,故 y = 3.5。
(float)a/b 依然是整數除法,會誤選 (A)。• 若誤以為
x = a / b 會自動幫你保留小數點,會誤選 (C) 或 (D)。
#include <stdio.h>
int main() {
char *s="ABC";
int i=10,CharPtrSize,CharSize;
CharPtrSize = (int)sizeof(s);
CharSize = (int)sizeof(*s);
printf("%d, %c", CharSize, *(s+2));
return 0;
}
🔍 逐步追蹤與誘答陷阱剖析
s 是字元指標 char*,在 64 位元系統上,sizeof(s) 是指標本身的記憶體長度 = 8 Bytes(存入 CharPtrSize,但 printf 並沒有印出此變數!這是出題老師設下的誘答陷阱)。2.
sizeof(*s):*s 代表指標指向的第一個字元 'A',其型態為 char,sizeof(char) 恆為 1 Byte,故 CharSize = 1。3.
*(s+2):s 指向字串 "ABC" 的開頭(位址 0 為 'A'、位址 1 為 'B'、位址 2 為 'C'),故 *(s+2) 即等同於 s[2],代表字元 'C'。4.
printf("%d, %c", CharSize, *(s+2)); 輸出 1, C,選 (C)。
CharPtrSize(8),且誤將 s+2 當成第二個字元('B')。• 選項 B/D:前後順序顛倒。
#include <stdio.h>
int main(){
int score[10] = {1, 2, 3, 4, 5, 6, 7, 0, 0, 0};
int i;
double sum = 0;
int average;
for(i=0; i<10; i++){
sum = sum + score[i]/10;
}
average = sum;
printf("average=%d", average);
return 0;
}
🔍 四個選項逐項深度剖析
score[i]/10!因為 score[i] 與 10 都是 int 整數,當分數小於 10 時(如 1~7),整數除法 score[i]/10 每次都直接截斷為 0,加進 sum 永遠都是 0。僅修改 average 的型態或格式字串無法解決迴圈內每次被截斷為 0 的問題。
① 在迴圈中將每個成績完整累加到
sum(sum = sum + score[i];),保留完整的總分(1+2+3+4+5+6+7 = 28)。② 迴圈結束後,再執行總分除以 10(
sum/10),由於 sum 是 double,會進行浮點數除法得到 2.8,轉型取整後為 2,成功修復錯誤!
score[i]/10,每次相加依然為 0。
🔍 四個選項逐項深度剖析
2. 32 位元無號整數(unsigned int):沒有負數,全部 32 個 bit 皆用來表示數值大小,因此最大值為 32 個位元全為 1,即 2³² - 1(約 42.94 億)。
故正確答案為 2³¹-1, 2³²-1,選 (D)。
• 混淆 16 位元(short)與 32 位元會誤選含有 2¹⁶ 的選項。
🔍 四個選項逐項深度剖析
char 只有 8 位元,範圍僅為 -128 ~ 127,遠遠裝不下 ±20000。float 與 double 浮點數不能加上 unsigned 修飾詞,語法不合法。short 是 16 位元有號整數,表示範圍為 -32,768 ~ 32,767,恰好能完美容納 -20000 ~ 20000 且最節省記憶體空間,為最佳選擇。* 代表指標(記憶體位址),且 unsigned 無法存放負數(-20000)。8,42,8a,接著執行 printf("%6.4f", X); 的結果為何?
printf("%d,%o,%x\n",(short int)X,(unsigned int)(X*4),(int)(X*16));
🔍 逆推數學推導三步驟
(short int)X 輸出十進位 8,代表 X 的整數部分為 8(排除選項 A 與 B)。2. 八進位換算:
(unsigned int)(X*4) 以八進位 %o 輸出 42。八進位 42 = 4×8¹ + 2×8⁰ = 十進位 34。
故
X * 4 截斷整數後為 34 → 34 ≤ X * 4 < 35 → 8.5 ≤ X < 8.75。3. 十六進位換算:
(int)(X*16) 以十六進位 %x 輸出 8a。十六進位 8a = 8×16¹ + 10×16⁰ = 128 + 10 = 十進位 138。
故
X * 16 截斷整數後為 138 → 138 ≤ X * 16 < 139 → 8.625 ≤ X < 8.6875。4. 代入驗證:令 X = 8.625:
• (short)8.625 = 8 (%d 印出 8) ✓
• 8.625 * 4 = 34.5 → 截斷為 34 = 八進位 42 (%o 印出 42) ✓
• 8.625 * 16 = 138.0 → 截斷為 138 = 十六進位 8a (%x 印出 8a) ✓
5.
printf("%6.4f", X); 輸出 4 位小數即為 8.6250,選 (C)。
10 高職段考與模擬精選實戰題(5 題全選項解析)
透過以下 5 題精選模擬試題,全面檢驗你對資料型態、溢位、字元運算與轉型的掌握度:
char c = 'b';,執行 printf("%c, %d", c - 32, c - 'a' + 1); 後的輸出結果為何?
🔍 四個選項逐項深度剖析
'b' 的 ASCII 碼為 98。c - 32 = 98 - 32 = 66,以 %c 字元格式輸出即為大寫字母 'B'。2.
c - 'a' + 1 = 'b' - 'a' + 1 = 98 - 97 + 1 = 2(代表 'b' 是字母表中的第 2 個字母)。故輸出 B, 2,選 (A)。
ans 的值為何?
int a = 5, b = 2;
double ans = a / b + 2.5;
🔍 四個選項逐項深度剖析
a / b。因為 a 與 b 都是 int,進行整數除法:5 / 2 = 2(小數點捨去!)。2. 接著進行加法
2 + 2.5:整數 2 自動提升為 double 2.0,加法結果為 4.5。故選 (B)。
5/2 會算出 2.5 再加 2.5 = 5.0,即掉入整數除法陷阱!signed char c = 127; c = c + 2; printf("%d", c);,螢幕將印出多少?
🔍 四個選項逐項深度剖析
signed char 的範圍是 -128 ~ 127。• 當
c = 127 加 1 時,發生溢位環繞到最小值 -128。• 再次加 1(即共加 2)時,數值由 -128 變成 -127。
故輸出 -127,選 (D)。
int arr[] = (10, 20, 30, 40, 50);,在 32 位元或 64 位元電腦上,運算式 sizeof(arr) / sizeof(arr[0]) 的計算結果為何?
🔍 四個選項逐項深度剖析
sizeof(arr) 是整個陣列的總 Bytes 數 = 5 個 int × 4 Bytes = 20 Bytes。•
sizeof(arr[0]) 是單一元素的大小 = 4 Bytes。•
20 / 4 = 5,這是 C 語言求出陣列長度的標準經典寫法!故選 (C)。
int val = 26;,若分別以 printf("%d,%o,%x", val, val, val); 輸出,結果為何?
🔍 四個選項逐項深度剖析
%d 十進位:輸出 26。2.
%o 八進位:26 ÷ 8 = 3 餘 2 → 輸出 32。3.
%x 十六進位:26 ÷ 16 = 1 餘 10 (10 在十六進位為 'a') → 輸出 1a。故輸出 26,32,1a,選 (A)。
11 考前衝刺 10 秒速記口訣 & 核心知識檢核清單
「整數除整數,小數必不復;若想要小數,轉型走前路!」
有號
int 是 2³¹ - 1,無號 unsigned 是 2³² - 1。
sizeof(指標) 在 64 位元必為 8;sizeof(*指標) 看指向型態。
'0' = 48,'A' = 65,'a' = 97,大小寫相差 32。
%d 十進位、%o 八進位、%x 十六進位。
float 佔 4 Bytes(約 7 位),double 佔 8 Bytes(約 15 位)。