1 陣列宣告與「未給值的元素自動補0」規則
陣列宣告時,可以只給部分元素的初始值——就像訂了一整排置物櫃(宣告的元素個數),但只把貼紙分配給前幾格(提供的初始值)。沒被分配到貼紙的置物櫃,C 語言會自動幫你貼上「0」,並不是空的、也不是垃圾值。
int arr[4] = {1, 2, 3}; // 元素個數宣告4個,只給3個值
printf("%d", arr[3]); // 未給值的 arr[3] 自動補0 → 印出 0
只要宣告陣列時有用 {...} 提供至少一個初始值,C 語言就會保證剩下沒給值的元素自動補0,這是語言明確保證的行為,不是未定義的垃圾值。統測很喜歡用這條規則設計「陣列宣告4個卻只給3個值,第4個是多少?」這類題目,答案永遠是0,不需要懷疑。
2 C 字串的本質:以 '\0' 結尾的 char 陣列
C 語言沒有專屬的「字串型態」,字串其實就是一個字元陣列,只是多了一個規定:內容的最後必須有一個特殊的空字元 '\0' 當作結束標記。printf 的 %s 就是靠這個標記知道要印到哪裡停下來。
char name[6] = "Alex"; // 字元陣列:'A','l','e','x','\0',(未用)
printf("%s", name); // 印到 '\0' 為止 → 印出 Alex
想像 %s 是一個只會「一直往下讀,讀到句號才停」的朗讀機器。陣列裡句號('\0')後面即使還留著沒被清掉的舊資料,也完全不會被讀到、不會被印出來——朗讀機器看到句號就停了。
字串常值 "Alex" 在記憶體裡實際存放的是 'A','l','e','x','\0' 共5個字元(別忘了算上結尾的 '\0'),char name[6] 多留的第6格目前沒被用到(若有給初始值以外的部分,同樣會自動補0)。宣告字元陣列時,記得預留的大小要「字串實際長度 + 1」才夠放結尾的 '\0'。
3 strlen/strcmp:字串內容比較不能用 ==
字串既然是陣列,陣列名稱在大部分情況下會退化成「指向第一個元素的指標」——這代表用 == 比較兩個字串陣列,比的其實是兩塊記憶體的位址是否相同,而不是「內容是否一樣」,幾乎不會是你要的結果。要比較字串內容,要改用標準函式庫的 strcmp();要知道字串長度,要用 strlen()。
#include <stdio.h>
#include <string.h>
int main(void) {
char a[] = "cat";
char b[] = "cat";
printf("strlen(a) = %zu\n", strlen(a)); // 3(不含結尾的'\0')
printf("strcmp(a,b) = %d\n", strcmp(a, b)); // 0代表兩字串內容相同
// if (a == b) 是常見錯誤!這樣比較的是兩個陣列的記憶體位址,不是內容
return 0;
}
strcmp(a,b) = 0
| 函式 | 作用 | 回傳值的意義 |
|---|---|---|
strlen(s) | 計算字串長度 | 字元個數,不含結尾的 '\0' |
strcmp(a,b) | 比較兩字串「內容」 | 0 代表內容完全相同;非0代表不同 |
a == b(陣列名稱) | 比較兩個指標的「位址」 | 幾乎必定是「假」,因為是兩塊不同的記憶體 |
4 二維陣列與二維字元陣列(中文字串表)的宣告與走訪
二維陣列可以想成「陣列的陣列」,第一個索引是列(row)、第二個是行(column)。統測特別愛用二維字元陣列(如 char S[10][4])存放一組固定長度的中文字串——每個中文字在UTF-8編碼下通常占3 bytes,加上結尾的 '\0' 共4 bytes,剛好對應行的大小。
int matrix[2][3] = { {1, 2, 3}, {4, 5, 6} };
for (int r = 0; r < 2; r++) {
for (int c = 0; c < 3; c++)
printf("%d ", matrix[r][c]);
printf("\n");
}
char S[9][4] = {"沖","收","脫","蓋","泡","沖","蓋","脫","送"};
// 索引:0=沖 1=收(干擾) 2=脫 3=蓋(干擾) 4=泡 5=沖(干擾) 6=蓋 7=脫(干擾) 8=送
for (int i = 0; i < 9; i += 2)
printf("%s", S[i]);
// 只印出偶數索引:沖脫泡蓋送(正確的燒燙傷急救步驟)
統測常把一組資料(例如急救步驟、密語)故意打亂順序、中間穿插干擾字,存進二維字元陣列裡,再考你「該用哪一組索引,才能依序組出正確的內容」。解題訣竅:先把陣列每個索引對應的內容抄下來列成清單,再逐一比對每個選項給的索引順序,實際模擬一次印出結果,不要用猜的。
5 陣列名稱退化成指標/*(p+i) 與 p[i] 的等價關係
陣列名稱在大部分運算情境下,會自動「退化」成一個指向第一個元素的指標。這代表 p[i] 與 *(p+i) 其實是完全等價的兩種寫法——只是換一種方式表達「往後跳 i 格,再把那格的值取出來」。
int arr[3] = {100, 200, 300};
int *p = arr; // 陣列名稱會自動退化成指向第一個元素的指標
printf("%d\n", *p); // 100
printf("%d\n", *(p + 1)); // 200,指標+1會依型態大小跳過一個int
printf("%d\n", p[2]); // 300,p[i]其實就是*(p+i)的另一種寫法
| 寫法 | 意義 | 等價寫法 |
|---|---|---|
*p | p目前指向位置的值 | p[0] |
*(p+1) | p往後跳1格,取該格的值 | p[1] |
p[i] | p往後跳i格,取該格的值 | *(p+i) |
1. 若 pData = &Data[2],則 *(pData+3) 指向的其實是 Data[2+3] = Data[5]——起始點會跟著指標當初指向的位置一起偏移,不是直接從 Data[3] 算起。
2. *n(n是陣列名稱)永遠等同於 n[0],是「陣列第一個元素」的另一種寫法,不是在對整個陣列做什麼特殊操作。
6 陣列+指標混合運算的常見陷阱
當陣列與指標混在一起、又加上變數遮蔽(shadowing)時,追蹤程式的難度會大幅提升。這裡整理兩個統測最愛的複合陷阱:
char *ptr = "Outside"; // 全域指標
int main(void) {
char str[20] = "This is a book";
char ptr[20] = "Main"; // 區域「陣列」,跟全域指標同名!
*ptr = *str; // 只改了ptr[0]這一個字元
printf("%s", ptr);
return 0;
}
main() 內重新宣告了一個同名的區域變數 ptr(這次是陣列,不是指標),這個區域 ptr 會遮蔽外層的全域指標 ptr。函式內所有用到 ptr 的地方,指的都是這個區域陣列 "Main",跟全域的 "Outside" 完全無關。
*ptr = *str 只改「一個字元」,不是整個字串
* 解參考一次只能存取、賦值一個字元。*ptr = *str 的意思是「把 str 的第一個字元,指定給 ptr 的第一個字元」,也就是 ptr[0] = str[0]。這裡把 ptr 原本的 'M' 換成了 str 的 'T',其餘字元(a, i, n)完全不受影響,結果是 "Tain",並不是把整個字串複製過去(那要用 strcpy())。
7 字元陣列的 ASCII 算術與陣列+迴圈的綜合追蹤
字元(char)在底層其實就是一個整數(ASCII碼),所以字元可以直接做加減運算——'x' + 1 會得到 ASCII 碼比 'x' 大1的下一個字元。這個技巧常跟迴圈、陣列自動補0混在一起出題。
int used[6] = {1, 2, 3, 4}, i; // used[4]、used[5] 自動補0
char name[6] = "Alex"; // A,l,e,x,'\0'
for (i = 1; i < 4; i++) {
used[i] = used[i] + 1;
name[i] = name[i] + 1; // 字元的ASCII碼加1,變成下一個字元
}
// name[3] 原為 'x',加1後是 ASCII 碼比 'x' 大1的字元 'y'
'A'~'Z'、'a'~'z'、'0'~'9' 這三組字元在 ASCII 表裡都是連續遞增排列的,所以 字元 + 1 一定會得到「字母順序上的下一個」字元(例如 'x'+1='y'、'A'+1='B'),但要小心:'z'+1 並不會神奇地繞回 'a',而是繼續往下一個 ASCII 碼(超出小寫字母範圍的符號),除非程式有額外寫繞回的邏輯。
遇到「陣列+迴圈+ASCII算術」綜合題,先把每個索引位置迴圈開始前的值列一欄,再把迴圈跑完後的值列另一欄,逐一核對哪些索引真的被迴圈的範圍(例如 i<4)覆蓋到、哪些沒有,才不會誤把初始值當成最終答案。
8 111~115 歷屆統測真題全選項深度剖析(共 12 題)
以下收錄統測專業科目(二)近年全部 12 題陣列與字串處理真題。每題均提供高解析度原始考題掃描圖、互動選項按鈕與所有選項逐項深入解析:
#include <stdio.h>
int main()
{
int Sum=0, Array[4]={1, 2, 3}, i;
for(i=1; i<4; i++)
Sum+=Array[i];
printf("%d", Sum);
return 0;
}
🔍 四個選項逐項深度剖析
i=0 到 i<3(也就是i=0,1,2),把索引整個往前平移了一格,於是加總了 Array[0]+Array[1]+Array[2]=1+2+3=6,而不是程式碼實際寫的 i=1 到 i<4(i=1,2,3),漏看了迴圈其實是從索引1開始,不是0。#include <stdio.h>
int main()
{
char Str[]="abcde";
char *ptr=Str;
printf("%s", ++ptr);
return 0;
}
🔍 四個選項逐項深度剖析
%s 只會印出指標目前指向的「單一字元」,而不是從該位置開始一路印到字串結尾的 '\0' 為止。%s 是逐一輸出字元直到遇到 '\0',並非只印一個字元,而且也沒有正確算出 ++ptr 之後指向的其實不是原本的 'a'。++ptr 之後指標指向的字元是 'b'(這部分邏輯正確),卻仍然誤解了 %s 的行為——%s 會從指標當下位置開始,一路印到 '\0' 為止,並不是只印出那一個字元。++ptr 沒有真正生效,或誤看成後置遞增 ptr++(後置遞增雖然也會移動指標,但整個運算式本身的「值」用的是移動前的舊位址),以為 printf 印的時候 ptr 還停留在原本指向 Str[0] 的位置。但程式碼寫的是前置遞增 ++ptr,會先讓 ptr 真正移動到 Str[1],才把這個「已經移動後」的位址傳給 printf。++ptr 先讓 ptr 移向 Str[1]('b'),才把這個新位址傳給 printf。%s 從該位址開始輸出,直到遇到 '\0' 為止,故輸出 "bcde",選 (D)。const int Count = ? ;
char Dictionary[50] = "IWhLoaorevYTeouTW5aM7iynwyuaTYn?";
char ShowMessage[12] ={0};
char *P = &Dictionary[0];
int Index = 0, Search = 0;
for(Index =0; Index < 11 ; Index++)
{
ShowMessage[Index] = P[Search];
Search += Count;
}
🔍 四個選項逐項深度剖析
Search 每輪都會維持0、永遠不變,代表 Index 從0跑到10這11輪,取出的字元全部都是 Dictionary[0],也就是重複印出11次 'I'("IIIIIIIIIII"),與目標字串 "ILoveTaiwan" 完全不符,說明 Count 絕不能是0(沒有真正跳躍讀取不同位置)。int TotalSteps = 5;
int Count = 0;
char StepName[9][4] = { "拖","脫","送","沖","蓋","泡","送" };
int Select[5] = {?};
for (Count = 0; Count < TotalSteps; Count+=1)
{
std::cout << StepName[Select[Count]];
}
🔍 四個選項逐項深度剖析
int Data[10] = {1,2,3,4,11,12,13,15};
int *pData = &Data[2];
🔍 四個選項逐項深度剖析
pData 指向 &Data[2],所以 pData[1] 等同於 *(pData+1) = Data[2+1] = Data[3] = 4,並不等於1。pData[1]==1 這個判斷式實際上是「假」,但選項卻宣稱它是「真」,敘述錯誤。pData 指向 Data[2],pData+3 正好指向 Data[2+3]=Data[5],所以 *(pData+3) 本質上就是在比較「Data[5] 跟它自己」,結構上恆為真(不管 Data[5] 實際存的是什麼值都一樣),敘述正確,選 (B)。Data[9] 確實等於0,Data[9]==0 這個判斷式實際上是「真」,但選項卻宣稱它是「假」,敘述錯誤。pData[5]=*(pData+5)=Data[2+5]=Data[7]=15;*(pData+2)=Data[2+2]=Data[4]=11;兩者相減 15-11=4,剛好等於 Data[3]=4,所以 Data[3]==(pData[5]-*(pData+2)) 這個判斷式實際上是「真」,但選項卻宣稱它是「假」,敘述錯誤。char StepName[5][4] = {"脫","蓋","送","沖","泡"};
void swap(char *a, char *b) {
char tmp;
for (x = 0; x < 3; x++) {
tmp = a[x];
a[x] = b[x];
b[x] = tmp;
}
}
int main(void) {
/* 行號13~15待填 */
for (i = 0; i<5 ;i++)
printf("%s", StepName[i]);
return 0;
}
🔍 四個選項逐項深度剖析
swap(StepName[2],StepName[5]) 中的索引5超出了陣列範圍(StepName 只宣告了5個元素,有效索引是0~4),這是存取未定義記憶體的危險寫法,並不能得到正確、安全的結果。char *ptr="Outside";
int main()
{
char str[20]="This is a book\0";
char ptr[20]="Main\0";
*ptr = *str;
printf("%s", ptr);
return 0;
}
🔍 四個選項逐項深度剖析
char *ptr="Outside",忽略了 main() 內部用 char ptr[20]="Main" 重新宣告了一個同名的區域陣列,這個區域 ptr 會遮蔽外層的全域指標,函式內所有的 ptr 都是指這個區域陣列,不可能是 "Outside"。*ptr = *str 的賦值方向弄反了,誤以為是把 ptr 的第一個字元 'M' 指定給 str(讓 str 的 'T' 被 'M' 取代變成 "Mhis...")。但程式碼寫的其實是「把 str 的第一個字元指定給 ptr」,被改變的是 ptr,不是 str。*ptr = *str 會把整個 str 字串內容整個複製給 ptr(就像呼叫了 strcpy() 一樣),但 * 解參考一次只能存取、賦值「一個字元」,這行只把 ptr 的第一個字元換成了 str 的第一個字元,並沒有複製整個字串。main() 內的區域陣列 char ptr[20] 遮蔽了全域指標 char *ptr,故程式中所有的 ptr 皆指向區域陣列 "Main"。*ptr = *str 只是把 str 第一個字元 'T' 指定給 ptr[0],把原本的 'M' 換成 'T',其餘字元(a, i, n)不變,ptr 變成 "Tain",選 (D)。char str[100] = "This is a book and that is a dog.\0";
char ans = 0, match_count=0;
char query[]="is";
int len = sizeof(query), i , j;
for(i=0; (i<100-len)&&(str[i]!='\0'); i++){
for(j=0; j<len-1; j++)
if(query[j]==str[i+j])
ans++;
else
break;
if(ans==len-1)
printf("%d-th match str[%d] !\n", ++match_count, i);
ans=0;
}
printf("%d, %d, %d", len, ans, match_count);
🔍 四個選項逐項深度剖析
sizeof(query) 是對字元陣列(含結尾 '\0')取大小,query 是 "is\0" 共3個bytes,故 len 固定為3,且完全不會隨比對過程改變。字串中出現連續 'i','s' 的位置有3處("This"裡、獨立單字"is"、"that is"裡),match_count 累加到3。外層迴圈每一輪結尾都會執行 ans=0;,所以不管中間怎麼變化,最終 ans 恆為0。輸出 "3, 0, 3",選 (B)。sizeof() 誤看成了 strlen()——sizeof(query) 算的是字元陣列配置的位元組數(含結尾 '\0'),固定是3,不會是0。ans=3 則是誤以為 ans 在比對到相符字串後不會被重置,忽略了外層迴圈每輪結尾都會執行 ans=0;,把 ans(單輪暫存用的計數器)跟 match_count(真正的總計數器)的用途搞混了。sizeof(query) 不包含字串結尾的 '\0',只算 "i" 和 "s" 兩個字元得到2,但 sizeof 對字元陣列而言,算的是配置的「所有」位元組數,包括結尾用來標記字串結束的空字元,所以是3,不是2(若要不含 '\0' 的字元個數,應該用 strlen())。int n[5]={1, 2, 3, 4, 5}, i;
n[1]=100;
*n = 1;
for(i=0; i<5; i++)
printf("%d", *(n+i));
🔍 四個選項逐項深度剖析
n[1]=100; 與 *n=1; 這兩行賦值敘述沒有真的生效,以為陣列從頭到尾都維持初始化時的 {1,2,3,4,5},忽略了這兩行都是會確實修改陣列內容的敘述——第一行把 n[1] 改成100,第二行把 n[0](也就是 *n)設為1(剛好跟原值相同,看起來沒變化)。n[1]=100; 後陣列變為 {1,100,3,4,5};*n 即 n[0],設定為1(值不變,因為原本就是1)。以 *(n+i)(等同 n[i])依序輸出各元素的值 "1","100","3","4","5",直接串接成 "1100345",選 (B)。*(n+i) 印出的數字依序串接成字串時,中途弄錯了串接順序,而不是把每一輪的完整輸出值依序、原封不動地接在後面。short i;
unsigned char count = 0, X = 0, Y = 0;
unsigned char x[8]= {1,1,1,1,1,1,1,0};
unsigned char y[8]= {0,1,1,1,1,1,1,1};
for(i = 7; i >= 0; i--){
if(x[i] != y[i])
count++;
X += x[i]*pow(2,7-i); //pow(a,b)傳回a的b次方值
Y += y[i]*pow(2,7-i);
}
🔍 四個選項逐項深度剖析
for(i=7;i>=0;i--),當 i 遞減到0時本體仍會執行(0>=0成立),執行完後還會再執行一次 i-- 讓 i 變成-1,直到 -1>=0 不成立才真正跳出迴圈,因此執行到行號13時 i 其實已經是-1,並不是還停留在0。i>=0 不成立(也就是 i=-1)才會停止,不會停在 i=1。short i;
unsigned char count = 0, X = 0, Y = 0;
unsigned char x[8]= {1,1,1,1,1,1,1,0};
unsigned char y[8]= {0,1,1,1,1,1,1,1};
for(i = 7; i >= 0; i--){
if(x[i] != y[i])
count++;
X += x[i]*pow(2,7-i);
Y += y[i]*pow(2,7-i);
}
printf("%.3f", (float)count/8);
🔍 四個選項逐項深度剖析
%.3f 的意思是「小數點前後總共固定輸出3位數字」,因而在整數部份前面多補了一個0。但 .3f 規定的其實是「小數點後固定輸出3位」,跟整數部份要印幾位完全無關,也不會在整數部份多補0。%.3f 會跟一般沒有指定精度的浮點數輸出一樣,只印出「剛好夠表示這個數值」的位數(0.25只需要兩位小數就能精確表示)。但 .3f 是明確要求小數點後固定輸出3位,即使第三位是0也一定要補上,應該是0.250,不是0.25。count=2。(float)count/8 = 2/8 = 0.25。%.3f 表示小數點後固定輸出3位,0.25補齊三位小數就是0.250,選 (C)。%.3f 也會像某些「補零到固定寬度」的格式化語法一樣,連整數部份也補一個0。事實上 %.3f 只規定小數點後的位數,並沒有規定整數部份要補零到幾位,0.25的整數部份就只有一位數 "0",不會多印一個0。int used[6] = {1, 2, 3, 4}, i;
char name[6] = "Alex";
for(i = 1; i < 4; i++){
used[i] = used[i] + 1;
name[i] = name[i] + 1;
}
🔍 四個選項逐項深度剖析
name[1]=name[1]+1 會把 'l' 的 ASCII 碼加1,變成 'm',並不是 'B'。'B' 其實是把 name[0]('A')加1才會得到的結果,這個選項可能把索引1誤看成了索引0。name[3]=name[3]+1,把 'x' 的 ASCII 碼加1,得到 ASCII 順序上的下一個字母 'y',選 (B)。used[1]=used[1]+1 這一行,把 used[1] 從2變成3。這個選項似乎誤以為迴圈完全沒有真正修改 used 陣列(把初始值直接當成最終值),忽略了迴圈本體確實會執行加1的動作。used[3]=used[3]+1 後,最終值應該是5,這個選項把初始值誤當成了最終值,忽略了迴圈本體對 used[3] 也確實執行了加1的動作(i=1,2,3三輪都會執行到,used[3]對應i=3那一輪)。9 高職段考與模擬精選實戰題(5 題全選項解析)
透過以下 5 題精選模擬試題,全面檢驗你對陣列補0、字串函式、二維陣列索引與指標算術的掌握度:
int arr[5] = {10, 20};
int i, sum = 0;
for (i = 0; i < 5; i++)
sum += arr[i];
printf("%d", sum);
🔍 四個選項逐項深度剖析
i<5,會確實跑滿5輪,把所有5個元素(含自動補0的那些)都加總進去,並不是只挑選有給初始值的元素。#include <stdio.h>
#include <string.h>
int main(void) {
char a[] = "hello";
char b[] = "help";
if (strcmp(a, b) == 0)
printf("相同");
else
printf("不同,strlen(a)=%zu", strlen(a));
return 0;
}
🔍 四個選項逐項深度剖析
strcmp(a,b) 是在比較兩字串「開頭幾個字元是否相同」,"hello" 與 "help" 確實開頭三個字元都是 "hel",但 strcmp 比較的是整個字串內容是否完全一致,兩者從第4個字元開始就不同('l' 對 'p'),strcmp 的回傳值不會是0,代表字串內容不同,應該走 else 分支。strcmp(a,b) 比較的是字串 "hello" 與 "help" 的完整內容,兩者不同,回傳值不為0,故執行 else 分支。strlen(a) 計算的是字串 a("hello")的字元長度,不含結尾的 '\0',共5個字元,故印出 "不同,strlen(a)=5",選 (B)。strlen() 會把字串結尾的 '\0' 也算進長度裡——"hello" 含 '\0' 確實共佔用6個bytes的記憶體空間沒錯,但 strlen() 回傳的是「不含結尾 '\0'」的字元個數,也就是5,不是6。這是把 strlen() 跟陣列實際佔用的記憶體大小(可用 sizeof 取得)搞混了。char Item[8][4] = {"筆","尺","橡皮擦","剪刀","膠水","釘書機"};
int Order[3] = {2, 4, 0};
for (int i = 0; i < 3; i++)
printf("%s", Item[Order[i]]);
🔍 四個選項逐項深度剖析
for(i=0;i<3;i++) 明明白白是從 Order[0] 開始、依序往後印到 Order[2],順序不會顛倒。int data[4] = {7, 14, 21, 28};
int *p = data;
printf("%d %d %d", *(p+2), p[1], *p);
🔍 四個選項逐項深度剖析
*(p+2) 等同於 data[2]=21;p[1] 是 *(p+1) 的另一種寫法,等同於 data[1]=14;*p 等同於 data[0]=7。依 printf 引數順序印出 "21 14 7",選 (A)。*(p+2), p[1], *p,必須照這個順序輸出,不能自行對調成由小到大排列。*(p+2) 誤算成了 data[3]=28(多加了1個索引),可能是把指標算術「+2」誤想成「移動到陣列的第2個之後那格」,而非「移動到索引為2的那格」。正確的 *(p+2) 就是 data[2],索引直接對應加的數字,不需要再多加1。p[1] 誤算成了1,可能是把 p[1] 誤讀成「指標p本身加1的結果」(也就是位址的偏移量本身),而不是「p[1]是*(p+1)的另一種寫法,代表陣列索引1位置存放的值」。p[1] 應該等於 data[1]=14,不是1。int score[5] = {60, 75};
char grade[5] = "ABCDE";
int i;
for (i = 1; i < 3; i++) {
score[i] = score[i] + 10;
grade[i] = grade[i] + 1;
}
printf("score[2]=%d, grade[2]=%c", score[2], grade[2]);
🔍 四個選項逐項深度剖析
i<3 讓 i=1,2 都會執行,i=2 這一輪 score[2]=score[2]+10,也就是0+10=10。grade[2] 原本是字元 'C'("ABCDE" 的第3個字母),i=2 這一輪 grade[2]=grade[2]+1 把 'C' 加1變成 'D'。故 score[2]=10, grade[2]=D,選 (A)。i<3 會讓 i=2 這一輪確實被執行到,兩個陣列在 i=2 這一輪都會被修改。i<3 讓 i=1 和 i=2 都會執行,grade[2] 也會被加1,從 'C' 變成 'D',不會維持原值 'C'。10 考前衝刺 10 秒速記口訣 & 核心知識檢核清單
有給部分初始值時,宣告個數多於給值個數的部分,一律自動補0,不是垃圾值。
字串就是以 '\0' 結尾的 char 陣列,%s 印到 '\0' 為止;strcmp 比內容,strlen 量長度,== 比位址。
p[i] 恆等於 *(p+i);若 p=&Data[2],則 *(p+3) 指向 Data[5],起點會跟著指標位移。
區域陣列與全域指標同名時,區域陣列會遮蔽全域指標,函式內用的一律是區域版本。
解參考賦值一次只動一個字元,不是整串複製,複製整串要用 strcpy()。
'A'~'Z'、'a'~'z'、'0'~'9' 各自連續遞增,字元+1會得到順序上的下一個字元。
先把每個索引對應的內容列成清單,再逐一模擬每個選項的索引順序,不要用猜的。