【C言語入門】scanfってなに？初心者向けにわかりやすく解説！

【C言語入門】scanfってなに？初心者向けにやさしく解説！

:::note warn
 **注意**  
 本記事の内容には、誤った知識や古い情報が含まれている可能性があります。  
 必ず公式ドキュメントや信頼できる参考書なども併せてご確認ください。
:::
---

:::note info
 **まだC言語の開発環境ができていない方へ**  
 この記事ではC言語の`scanf`について解説していますが、**まだC言語の開発環境（コンパイラやエディタ）が整っていない方**は、まず環境構築から始めましょう。  
 特にWindowsユーザーの方は、以下の記事が参考になります。  
 [VSCodeにC言語の開発環境を構築するには？（Qiita）](https://qiita.com/Ayanokoji/items/60b6873c3bc00084eeba)  
  
 この記事では、**Visual Studio Code（VSCode）とMinGW**を使ったC言語開発環境の作り方が、初心者向けに丁寧に解説されています。  
  
 **環境構築が完了したら、この記事の内容を参考にC言語のプログラムを書いてみましょう！**
:::

C言語を始めたばかりの友人から「scanfがよくわからない」と相談されました。  
この記事では、C言語でよく使うscanf（スキャンエフ）という関数について、専門用語も使いながら、例えや図解を交えて、なぜそうなるのか・つまずきやすいポイントも一緒に解説します。

---

## scanfとは？

scanfは、C言語で「キーボードから数字や文字を入力してもらう」ための関数です。  
たとえば、ゲームで「名前を入力してください」と出る場面を思い浮かべてください。  
scanfは、まさにその「入力」をプログラムで受け取るための道具です。

### 専門用語で言うと…

- **標準入力（stdin）**：キーボードからの入力のこと
- **関数**：何か特定の仕事をしてくれる命令のまとまり

---

## 使い方の基本

scanfの使い方は、次のようになります。

```c
scanf("フォーマット", &変数);
```

たとえば、数字を入力してもらう場合はこう書きます。

```c
int num;
scanf("%d", &num);
```

### 例え話

「num」という箱に、scanfがキーボードから受け取った数字を入れてくれるイメージです。  
scanfは「どの箱に入れればいい？」と聞いてくるので、「この箱（num）だよ！」と教えてあげる必要があります。

---

## &（アドレス演算子）が必要な理由

ここが初心者が一番つまずきやすいポイントです！

### なぜ&が必要なの？

scanfは「値そのもの」ではなく、「値を入れる場所（アドレス）」を知りたがります。  
例えるなら、「荷物（入力された数字）をどこに置けばいい？」と聞かれている感じです。  
&は「この箱の住所はここだよ！」と教えるための記号です。

- `num`：箱の名前
- `&num`：「numという箱の住所」

### よくある間違い

- `scanf("%d", num);` ← これはダメ！  
  これだと「箱の名前」しか伝わらず、「住所」がわからないので、scanfは正しく動きません。

- `scanf("%d", &num);` ← これが正解！  
  変数numの「住所」を渡すことで、scanfが正しく値を格納できます。

---

## よく使うフォーマット指定子

C言語のscanfでは、「どんな種類のデータを入力してもらうか」を**フォーマット指定子**で指定します。  
これは「どんな箱に入れるか」をscanfに伝えるためのラベルのようなものです。

| 指定子 | 意味 | 例 |
|--------|------|----------------------|
| %d     | 整数（int） | scanf("%d", &num); |
| %f     | 小数（float） | scanf("%f", &f); |
| %lf    | 倍精度（double） | scanf("%lf", &d); |
| %s     | 文字列 | scanf("%s", str); |
| %c     | 1文字 | scanf("%c", &ch); |

### 例え話

- **%d**は「整数用の箱」
- **%f**は「小数用の箱」
- **%s**は「文字列用の箱」
- **%c**は「1文字用の箱」

### つまずきポイント

- **%s（文字列）だけは&がいらない！**  
  文字列は「箱の住所（配列名）」そのものがすでに住所になっているからです。  
  例：`scanf("%s", str);` ← &は不要

---

## 複数の値を一度に読み取る

scanfは、一度に複数の値を読み取ることもできます。

```c
int a, b;
scanf("%d %d", &a, &b);
```

この場合、キーボードで「10 20」と入力すると、aに10、bに20が入ります。

### 例え話

「2つの箱（aとb）を用意して、scanfが順番に荷物（入力値）を入れてくれる」イメージです。

### つまずきポイント

- 入力時は**スペースや改行で区切る**必要があります。
- 入力の順番とフォーマット指定子の順番が一致していないと、正しく値が入りません。

---

## 注意点と落とし穴

### スペース区切りでの入力

scanfは、スペースやEnter（改行）で入力の区切りを判断します。  
たとえば「10 20」と入力してEnterを押すと、10がaに、20がbに入ります。

### 文字（%c）を読むときの落とし穴

直前のscanfでEnterキーが押されていると、その「Enter（改行）」が%cで読まれてしまうことがあります。  
→ 対策として、`getchar()`で余分な改行を読み飛ばす方法があります。

### エラー処理を忘れがち

scanfは、正しく入力できたかどうかを**戻り値**で教えてくれます。

```c
if (scanf("%d", &num) != 1) {
    printf("数字の入力に失敗しました。\n");
}
```

#### scanfの戻り値とは？

scanfは「正しく読み取れた値の個数」を返します。  
たとえば、`scanf("%d %d", &a, &b)`の場合、2つの整数が正しく入力されれば2を返します。  
もし1つしか正しく入力できなかった場合は1、どちらも失敗した場合は0が返ります。

**失敗例：**
```c
int num;
if (scanf("%d", &num) != 1) {
    printf("数字の入力に失敗しました。\n");
}
```
このとき、たとえば「abc」と入力すると、数字として読み取れないため0が返り、エラー表示されます。

**対策例：**
```c
scanf("%d", &num);
getchar(); // 改行を読み飛ばす
scanf("%c", &ch); // 本来の文字を読む
```

### つまずきポイントまとめ

- **&を忘れる**
- **%sだけは&がいらない**
- **入力の区切り（スペースや改行）に注意**
- **%cの直前に余分な改行が残っていないか注意**
- **エラー処理を忘れずに**

### %sの危険性と安全な使い方

`s`指定子で文字列を読み取るとき、配列の大きさより長い文字列を入力されると**バッファオーバーフロー**が起き、プログラムが異常終了したり、セキュリティ上の問題になることがあります。

**安全な書き方：**
```c
char str[10];
scanf("%9s", str); // 最大9文字＋終端文字で安全
```
このように、`%9s`のように最大文字数を指定しましょう。

---

## 実践的なコード例：電卓風プログラム

では、実際に2つの整数を読み取り、それらの和・差・積・商を出力する簡単な電卓プログラムを作ってみましょう。

```c
#include <stdio.h>

int main() {
    int a, b;
    printf("2つの整数をスペースで区切って入力してください: ");
    if (scanf("%d %d", &a, &b) != 2) {
        printf("入力エラーです。\n");
        return 1;
    }

    printf("足し算: %d + %d = %d\n", a, b, a + b);
    printf("引き算: %d - %d = %d\n", a, b, a - b);
    printf("掛け算: %d * %d = %d\n", a, b, a * b);
    if (b != 0) {
        printf("割り算: %d / %d = %d\n", a, b, a / b);
    } else {
        printf("割り算: 0では割れません！\n");
    }

    return 0;
}
```

### 例え話

- 「a」と「b」という2つの箱に、scanfで数字を入れてもらいます。
- その後、足し算・引き算・掛け算・割り算をして結果を表示します。

### 入力例と出力例

#### 例1：2つの整数を入力する場合

**入力例**
```
10 20
```

**出力例**
```
足し算: 10 + 20 = 30
引き算: 10 - 20 = -10
掛け算: 10 * 20 = 200
割り算: 10 / 20 = 0
```

#### 例2：入力ミスの場合

**入力例**
```
abc 20
```

**出力例**
```
入力エラーです。
```

---

## まとめ

- **scanfはC言語で標準入力（キーボード入力）を受け取るための関数**です。
- **&（アドレス演算子）を忘れずに！** ただし、文字列（%s）は例外で&不要。
- **フォーマット指定子**（%d, %f, %s, %cなど）で入力の型を指定します。
- **複数の値も一度に読み取れる**が、入力順や区切りに注意。
- **%cで改行が読まれる落とし穴**や、**%sのバッファオーバーフロー**にも注意しましょう。
- **scanfの戻り値でエラー処理**を行うことで、より安全なプログラムになります。

初心者がつまずきやすいポイントを押さえつつ、実践的な使い方や注意点も紹介しました。  
この記事を参考に、scanfの使い方をしっかりマスターしてください！