Skip to main content

*2.5 C語言的 scanf 格式化輸入

我們已經學會如何用 printf 讓程式輸出精美的訊息。但一個真正有用的程式,不僅要會「說」,更要會「聽」。它需要接收使用者的指令、數據,才能進行下一步的處理。

scanf (scan formatted) 就是這座溝通的橋樑。它會暫停程式的執行,靜靜地等待使用者從鍵盤輸入資料,然後依照我們指定的「格式」去解析這些輸入,並將它們存放到對應的變數中。

同樣地,要使用 scanf,請務必在程式開頭引用標頭檔:

#include <cstdio>

2.5.1- scanf 的核心語法與「&」的秘密

scanf 的語法看起來和 printf 有點像,但有一個關鍵且絕對不能忘記的區別。

scanf("格式化字串", &變數1, &變數2, ...);
    格式化字串: 由一或多個「格式指定符」組成,用來告訴 scanf 使用者將會輸入什麼類型的資料。例如,"%d" 代表使用者會輸入一個整數。 & (取址運算子): 這是 scanf 最重要、也最容易出錯的地方!

    讓我們用一個生活化的比喻來理解:

    想像一下,變數是一個「置物櫃」,裡面可以存放資料。

      當你使用 printf("%d", score); 時,你是告訴 printf:「打開 score 這個櫃子,把裡面的東西(值)拿出來秀給大家看。」 當你使用 scanf("%d", &score); 時,你是告訴 scanf:「我給你 score 這個櫃子的地址(&score),請你把使用者輸入的東西,親自送到這個地址的櫃子裡放好。」

      scanf 需要的是「存放資料的地址」,而不是「變數裡現有的值」。所以,除了字串陣列(我們稍後會提)以外,幾乎所有變數在使用 scanf 時都必須在前面加上 & 符號!

      2.5.2- scanf 的各種應用與常見陷阱

      常用的格式指定符:

      指定符 對應資料類型 說明 %d int 讀取一個十進位整數。 %f float 讀取一個浮點數。 %lf double 注意! 讀取 double 類型時要用 %lf (long float),這是新手常犯的錯誤。 %c char 讀取一個單一字元。 %s 字串 (char 陣列) 讀取一個字串(但遇到空白、Tab或換行時會停止)。

      範例 1:讀取學生的基本資料

      #include <cstdio>
      
      int main() {
          int age;
          double height;
      
          printf("請輸入你的年齡:");
          scanf("%d", &age);
      
          printf("請輸入你的身高 (公尺):");
          scanf("%lf", &height); // 讀取 double,使用 %lf
      
          printf("好的,你 %d 歲,身高 %.2f 公尺。\n", age, height);
          return 0;
      }
      

      執行過程:

      請輸入你的年齡:17 (使用者輸入後按 Enter) 請輸入你的身高 (公尺):1.75 (使用者輸入後按 Enter) 好的,你 17 歲,身高 1.75 公尺。

      你可以在格式化字串中放置多個指定符,scanf 會要求使用者一次輸入多個值,並用空白、Tab 或換行鍵來分隔它們。

      範例 2:輸入座標

      #include <cstdio>
      
      int main() {
          int x, y;
          printf("請輸入一個二維座標 (例如: 15 30):");
          scanf("%d %d", &x, &y);
          printf("你輸入的座標點為 (%d, %d)\n", x, y);
          return 0;
      }
      

      執行過程:

      請輸入一個二維座標 (例如: 15 30):15 30
      你輸入的座標點為 (15, 30)
      

      這是 scanf 最經典的陷阱!當你讀取完一個數字後,緊接著要讀取一個字元時,常常會出問題。

      範例 3 (錯誤示範):

      #include <cstdio>
      
      int main() {
          int choice;
          char confirm;
          printf("請選擇項目 (1-3): ");
          scanf("%d", &choice);
          printf("你確定嗎? (Y/N): ");
          scanf("%c", &confirm); // 這行會出問題
          printf("你的選擇是 %d, 確認字元是 '%c'\n", choice, confirm);
          return 0;
      }
      

      執行過程:

      請選擇項目 (1-3): 2 (使用者輸入 2 後按 Enter) 你確定嗎? (Y/N): 你的選擇是 2, 確認字元是 ' '

      問題分析:

      當你輸入 2 並按下 Enter 鍵時,你其實輸入了兩個字元:'2' 和 '\n' (換行符號)。

      scanf("%d", ...) 只讀走了 '2',那個 '\n' 還留在輸入緩衝區中。輪到 scanf("%c", ...) 時,它立刻把還留著的 '\n' 讀走了,導致程式根本不等待你輸入 Y 或 N。

      解決方案:

      在 %c 前面加一個空格," %c"。這個空格會告訴 scanf:「請忽略前面所有空白類的字元(包含空格、Tab、換行符),然後再讀取下一個真正的字元。」

      範例 3 (正確寫法):

      #include <cstdio>
      int main() {
          int choice;
          char confirm;
          printf("請選擇項目 (1-3): ");
          scanf("%d", &choice);
          printf("你確定嗎? (Y/N): ");
          scanf(" %c", &confirm); // 在 %c 前加一個空格
          printf("你的選擇是 %d, 確認字元是 '%c'\n", choice, confirm);
          return 0;
      }
      

      %s 雖然方便,但它遇到任何空白字元(空格、Tab、換行)就會停止讀取。

      範例 4:讀取姓名

      #include <cstdio>
      
      int main() {
          char name[30];
          printf("請輸入你的英文全名 (例如: Peter Pan): ");
          scanf("%s", name); // 注意:字串陣列 name 本身就是地址,所以不用加 &
          printf("你好, %s!\n", name);
          return 0;
      }
      

      執行過程:

      請輸入你的英文全名 (例如: Peter Pan): Peter Pan 你好, Peter!

      問題分析:

      scanf 只讀到了 "Peter" 就因為遇到空格而停止了,"Pan" 則被留在了後面。

      這也是為什麼在 C++ 中,當需要讀取一整行含有空格的文字時,我們未來會學習更適合的 cin.getline() 或 fgets() 函式。

      2.5.3- 總結與速查表

      scanf 是程式接收輸入的基礎,雖然有些小陷阱,但只要小心使用,它依然非常強大。

      指定符 對應資料類型 關鍵提醒 %d int 變數前記得加 &。例如 scanf("%d", &num); %f float 變數前記得加 &。例如 scanf("%f", &price); %lf double 務必使用 %lf,而非 %f。變數前記得加 &。例如 scanf("%lf", &pi); %c char 變數前記得加 &。若前面有其他輸入,建議用 " %c" 來清除換行符。 %s char[] 變數前不用加 &。只能讀取不含空白的字串。

      2.5.4- 練習題作業

      練習題 1:華氏溫度轉換
        目標: 練習讀取浮點數 (double) 並進行計算。 說明: 請使用者輸入攝氏溫度,程式將其轉換為華氏溫度後輸出。 公式: 華氏 = 攝氏 * 9 / 5 + 32 執行範例:
        請輸入攝氏溫度:25.0
        轉換後的華氏溫度為:77.0
        

        練習題 2:簡易對話程式
          目標: 綜合練習 %d, %s。 說明: 撰寫一個程式,詢問使用者的名字和學號,然後向他打招呼。 執行範例:
          你好!請問你叫什麼名字? (請輸入英文名) David 你的學號是幾號? 10123 你好, David (學號: 10123),歡迎使用本系統!

          練習題 3:解決字元輸入問題
            目標: 練習處理 %c 的換行符陷阱。 說明: 撰寫一個程式,讓使用者輸入一個整數代表分數,然後再輸入一個字元代表評等 (A/B/C/D)。最後將兩者一起輸出。請務必確保程式能正確等待使用者輸入評等。 執行範例:
            請輸入你的分數:88 請輸入你的評等 (A-F):A 你的成績是 88 分,評等為 A。