# C Language / Fromatted Input & Output
## 概述
C 語言中,所有輸入和輸出操作都是透過串流(stream) 進行,串流是一序列的位元組(bytes)。在輸入操作中,位元組從裝置(如鍵盤、磁碟機、網路連線等)流向主記憶體。在輸出操作中,位元組從主記憶體流向裝置(如顯示器螢幕、印表機、磁碟機、網路連線等)。
當程式執行開始時,會自動連接三個串流:
- 標準輸入串流連接到鍵盤
- 標準輸出串流連接到螢幕
- 第三個串流(標準錯誤串流)也連接到螢幕
好其實這章節就是在說 scanf 和 printf 函數的格式化功能,然後要包含標頭檔`<stdio.h>`。不能說是枯燥乏味,~~只能說是無聊至極~~。
## Ch01 / printf 函數
printf 可以精確地格式化輸出。每一次呼叫printf都需要一個格式控制字串(format control string),描述輸出格式。格式控制字串包含了轉換字元、旗標、欄位寬度、精度和文字字元。這些元素與百分號(%)組合而成轉換規範(conversion specification)。
printf 函數具有以下格式化能力:
- 將浮點數四捨五入到指定的小數位數
- 將輸出右對齊和左對齊
- 以指數格式表示浮點數
- 以八進制和十六進制格式表示無號整數
- 以固定的欄位寬度和精度顯示所有類型的資料
printf 函數的格式為:
```c
printf(格式控制字串, 其他參數);
```
格式控制字串描述輸出格式,而其他參數(可選)對應於格式控制字串中的每個轉換規範。每個轉換規範以百分號開頭,並以轉換字元結尾。一個格式控制字串可以包含多個轉換規範。
### 1. 整數轉換規範
整數是不含小數點的整數,可以用幾種不同的格式顯示,以下程式範例使用每個整數轉換字元印出一個整數:
```c=
#include <stdio.h>
int main(void)
{
int x = 459;
printf("%d\n", x); /* 459 */
printf("%i\n", x); /* 459 */
printf("%o\n", x); /* 713 */
printf("%u\n", x); /* 459 */
printf("%x\n", x); /* 1cb */
printf("%X\n", x); /* 1CB */
/* 僅減號會被印出,加號通常會被隱藏 */
printf("%d\n", -x); /* -459 */
/* 將-455視為無號整數時,其值為4294966841 */
printf("%u\n", -x); /* 4294966841 */
return 0;
}
```
| 格式控制符 | 說明 |
|-------|------|
| `%d`和`%i` | 印出十進制整數 |
| `%o` | 八進制整數 |
| `%u` | 印出無號十進制整數 |
| `%x` | 印出小寫十六進制整數 |
| `%X` | 印出大寫十六進制整數 |
> note:當將負數以`%u`無號整數格式印出時,會得到一個大於等於2^32的值
### 2. 浮點數轉換規範
浮點數包含小數點,程式中通常會使用指數表示法 + 轉換字元`e`和`E`來顯示浮點數,這相當於數學中使用的科學記號法。
例如,150.4582可以用科學記號法表示為1.504582 * 10^2,或用指數記號法表示為1.504582E+02。這表示1.504582乘以10的2次方(E+02),E代表"指數"。
使用轉換字元`e`、`E`和`f`時,預設顯示小數點右側有6位數的精度。`f`會確保在小數點左側至少有一位數字,而`e`和`E`則會在指數前分別印出小寫e和大寫E,並且在小數點左側只會有一位數字。
轉換字元`g`(或`G`)會根據數值大小,自動選擇使用`e`(或`E`)或`f`格式,且不會印出尾隨的0(如1.234000會被印為1.234)。
說了這麼多密密麻麻的一大堆,還是直接看程式範例比較快:
```c=
#include <stdio.h>
int main(void)
{
float x = 459.683;
printf("%e\n", x); /* 4.596830e+02 */
printf("%E\n", x); /* 4.596830E+02 */
printf("%f\n", x); /* 459.683000 */
printf("%g\n", x); /* 459.683 */
printf("%G\n", x); /* 459.683 */
/* 根據指數的值,決定使用e或f格式 */
printf("%g\n", 0.0000875); /* 8.75e-05 */
printf("%g\n", 8750000.0); /* 8.75e+06 */
printf("%g\n", 8.75); /* 8.75 */
printf("%g\n", 87.5); /* 87.5 */
/* 精度表示最多顯示幾位有效數字(包含整數部分) */
printf("%g\n", 1234567.0); /* 1.23457e+06 */
return 0;
}
```
| 格式控制符 | 說明 |
|-------|------|
| `%e`和`%E` | 分別使用小寫e和大寫E印出指數格式的浮點數 |
| `%f` | 以定點表示法印出浮點數,不會四捨五入 |
| `%g`和`%G` | 根據數值大小自動選擇`e`(或`E`)或`f`格式,並移除尾隨的0,其精度控制預設為6 |
## Ch02 / scanf函數
scanf函數可以精確格式化輸入。每一次呼叫 scanf 都需要一個格式控制字串,描述要讀入的資料格式。格式控制字串包含了轉換字元和文字字元。
scanf函數具有以下輸入格式化能力:
- 讀入所有類型的資料
- 從輸入串流讀取特定字元
- 在輸入串流中跳過特定字元
scanf函數的格式為:
```c
scanf(格式控制字串, 其他參數);
```
格式控制字串描述輸入格式,而其他參數是將要存放輸入資料的變數位址。
以下是常用的轉換字元:
| 轉換字元 | 說明 |
|-------|------|
| `%c` | 讀取一個字元 |
| `%d` | 讀取一個十進制整數 |
| `%i` | 讀取一個整數(十進制、八進制或十六進制) |
| `%f` | 讀取一個浮點數 |
| `%lf` | 讀取一個double型浮點數 |
| `%s` | 讀取一個字串 |
| `%x` | 讀取一個十六進制整數 |
## Ch03 / 程式範例
### 範例1:讀取並印出整數
```c=
#include <stdio.h>
int main(void)
{
int x, y, z;
printf("請輸入三個整數(用空白隔開):");
scanf("%d %d %d", &x, &y, &z);
// 使用 %d 轉換字元讀取三個十進制整數到變數x、y和z
printf("你輸入的三個整數為: %d, %d, %d\n", x, y, z);
return 0;
}
```
### 範例2:計算圓面積
```c=
#include <stdio.h>
#include <math.h>
int main(void)
{
const double PI = 3.14159265358979323846;
double radius, area;
printf("請輸入圓的半徑: ");
scanf("%lf", &radius);
// 使用 %lf 轉換字元讀取一個double型浮點數到radius變數
area = PI * radius * radius;
printf("圓的面積為: %.2f\n", area);
// 使用`%.2f`印出圓面積到小數點後兩位
return 0;
}
```
### 範例3:讀取並反轉字串
```c=
#include <stdio.h>
#include <string.h>
void reverseString(char str[]);
int main(void)
{
char str[100];
printf("請輸入一個字串: ");
scanf("%s", str);
printf("原始字串: %s\n", str);
reverseString(str);
printf("反轉後字串: %s\n", str);
return 0;
}
void reverseString(char str[])
{
int length = strlen(str);
int i, j;
char temp;
for (i = 0, j = length - 1; i < j; i++, j--)
{
temp = str[i];
str[i] = str[j];
str[j] = temp;
}
// 不斷交換首尾字元,直到遇到中間
}
```
---
*註: 部分內容截自於網路,此筆記非完全原創。*
***Latest Updated On:2024.05.31,
published with the of LICENSE of WTFPL
Author:Qaron(呱呱)***