---
# System prepended metadata

title: C  Tutorial - I/O

---


# C語言教學 —— 輸入及輸出

::: info
本教學由 @watermelon1024 ||和 @ChatGPT 共同||製作。
:::


# 前言

我們都知道，不管是遊戲還是工具，程式就是要和螢幕前的使用者互動，與使用者進行交流以及從使用者那裡獲取資訊是一項重要的任務，那麼，我們要怎麼和使用者溝通呢？
這就是我們今天要學習的內容 —— <font color="#61afef">**輸入與輸出**</font>。

### 輸入與輸出

要在C語言中輸入與輸出，我們需要先知道該怎麼讓程式「學會」輸入與輸出，就像人從小也要學習怎麼說話一樣。
要讓程式學會怎麼輸入與輸出，我們就需要派出一個工具 —— <font color="#c678dd">**標頭檔**(Header File)</font>。

## 標頭檔

在C程式設計中，**標頭檔**是一種包含了 {==預定義函式==|functions} 、 {==變數==|variables} 和 {==常數==|constants} 聲明的檔案。它們允許你在程式中使用這些預定義的元素，而無需從頭開始重新編寫它們。

### 使用標頭檔

標頭檔通過前置處理器的 `#include` 指令==包含==(可以理解成==匯入==)到您的程式中。

例如：
```c
#include <stdio.h>
```

### *<stdio.h>*

名詞解釋：
- *std*：是"Standard"的縮寫，中文譯為「標準」。
- *io* ：是"Input/Output"的縮寫，中文譯為「輸入/輸出」。
- *.h* ：是標頭檔(++H++eader File)的副檔名。


`<stdio.h>` 就是包含了用於**標準==輸入==和==輸出==操作**的函數和常量聲明的標頭檔，而我們這次要使用的`scanf`和`printf`就是其內的函式。


# 輸出 —— `printf()`

`printf` 函數是以{==格式化==|++f++ormatted}的方式將資料輸出到螢幕。通過構建==格式控制字串==，可以將各種型態的資料插入到輸出文本中。

以下是一些常見的格式預留位置：
- `%d`：用於輸出{==整數==|integer}，`d` 為 `digit`(數字)的縮寫。
- `%f`：用於輸出{==浮點數==(小數)|++f++loat / double}。
- `%c`：用於輸出{==字元==|++c++haracter}。
- `%s`：用於輸出{==字串==(字元陣列)|++s++tring}。

讓我們看一個範例：
```c=
#include <stdio.h>

int main() {
    int num = 16;
    float pi = 3.14159;
    char letter = 'A';
    char name[] = "Apple";

    printf("Integer: %d\n", num);
    printf("Float: %f\n", pi);
    printf("Character: %c\n", letter);
    printf("String: %s\n", name);

    return 0;
}
```
這段程式碼會輸出：
```
Integer: 16
Float: 3.141590  // *註： %f 預設輸出是小數點後6位，詳見下方的進階學習。
Character: A
String: Apple
```

---

::: spoiler 進階學習 —— 進階版格式化字串

### 格式化字串中的特殊格式控制符

使用 `printf` 函數時，我們可以在上方學到的基礎格式控制符中，再加入一些特殊的格式控制符，以達到控制浮點數的==小數點位元數==和==整數的最小欄位寬度==：

- `%f`：用於輸出==浮點數==，預設情況下會顯示{==6位元小數==|小數後6位}。
    例如：`printf("%f", 3.14159);` 將會輸出 `3.141590`。
- `%.nf`：透過 `.n` ( `n` 為一整數)，可以控制輸出的==小數點後的位數==。
    例如：`printf("%.2f", 3.14159);` 將會輸出 `3.14`，只顯示2位小數。
- `%m.nf`：結合 `m` 與 `n` ( `m`、`n` 皆為一整數)，可以控制輸出的==整個數位的最小欄位寬度==和==小數點後的位數==。

    ::: info
    位數的欄位寬度：==整數\+小數點1格\+小數==的總長度。當這三個加起來長度不足設定值的最小欄寬度，則預設在前方補==空白==直到符合最小欄位寬度；若長度超過設定值，則照常輸出，不會刪減數字。
    :::
    例如：`printf("%6.2f", 3.14159);` 將會輸出 `  3.14`，總寬度為6，前方2格空白，小數點後2位。
    例如：`printf("%4.2f", 123.456);` 將會輸出 `123.46`，由於數字位數(共6位)超過最小欄位寬度(4位)，因此全部輸出，而小數點後則輸出2位。
- `%md`：通過 `m` 可以控制輸出的==整數的最小欄位寬度==。
    例如：`printf("%5d", 42);` 將會輸出 `   42`，總寬度為5，前方3格空白。

下方是一些範例，展示了如何使用這些特殊的格式控制符：
```c=
#include <stdio.h>

int main() {
    float pi = 3.14159;
    int num = 42;

    printf("Float with default precision: %f\n", pi);
    printf("Float with 2 decimal places: %.2f\n", pi);
    printf("Float with width and 2 decimal places: %8.2f\n", pi);

    printf("Integer: %d\n", num);
    printf("Integer with width: %5d\n", num);

    return 0;
}
```
結果：
```
Float with default precision: 3.141590
Float with 2 decimal places: 3.14
Float with width and 2 decimal places:     3.14
Integer: 42
Integer with width:    42
```

||<small>感謝 @ChatGPT 協助撰寫</small>||
:::


# 輸入 —— `scanf()`

`scanf` 函數是以{==格式化==|++f++ormatted}的方式從使用者輸入中讀取資料。與 `printf` 類似(除了double，詳見下方說明)，需要構建==格式控制字串==，並使用格式預留位置來指定要讀取的資料類型。
需要注意的是， `scanf` 需要使用「==取址運算子 `&`==」來傳遞變數的記憶體位址，以便將輸入的值存儲到變數中。(這裡要講清楚會有點複雜，所以先記起來要用 `&` 就好)

- `%lf`：用於輸入{==雙精度浮點數==|double / long double}。

    ::: info
    在C語言中，`%f` 可以用於==輸入和輸出 float== 以及==輸出 double==；`%lf` 則是專門用於==輸入 double / long double==。
    在C++中，`%lf` 和 `%f` 都可以用於==輸入和輸出 double==。
    :::


看下方例子：
```c=
#include <stdio.h>

int main() {
    int num;
    double f;

    printf("Enter an integer: ");
    scanf("%d", &num);

    printf("Enter a double: ");
    scanf("%lf", &f);

    printf("Entered integer: %d\n", num);
    printf("Entered double: %lf\n", f);  // 這裡用 %f 也可以正常輸出

    return 0;
}
```
結果：
```
Enter an integer: 314
Enter a double: 2.71828182846
Entered integer: 314
Entered double: 2.718282  // %f, %lf 預設輸出皆是小數後6位
```


# 總結

`printf` 和 `scanf` 函數是C語言中處理==輸入和輸出的關鍵==。通過瞭解這兩個函數的使用方法，可以更加輕鬆地處理格式化的輸入和輸出，為你的程式增添更多的功能和交互性。希望這次的教學能夠幫助你更好地掌握這些重要的C語言概念！

||<small>我懶著寫結語了，所以這段是ChatGPT寫的</small>||

---

{%hackmd Wd1xvc_AQuSzWZPcQXSn3Q %}
<!-- the theme made by Luminous-Coder -->