入力と出力

入力と出力はあなたとコンピュータの会話のようなものです——printf はコンピュータからあなたへの語りかけ、scanf はあなたからコンピュータへの語りかけです。フォーマットを間違えると会話が噛み合いません。

printfフォーマット出力

printf は「print formatted」の略です。最初の引数はフォーマット文字列で、その後に出力する値が続きます。

基本フォーマット指定子

指定子 目的 出力
%d 10 進整数 printf("%d", 42) 42
%f 浮動小数点 printf("%f", 3.14) 3.140000
%c 単一文字 printf("%c", 'A') A
%s 文字列 printf("%s", "hi") hi
%x 16 進 printf("%x", 255) ff
%o 8 進 printf("%o", 8) 10
%p ポインタアドレス printf("%p", &a) アドレス値
%% パーセント記号そのもの printf("100%%") 100%
C
#include <stdio.h>

int main(void) {
    int age = 25;
    float height = 175.5f;
    char grade = 'A';
    printf("年齢: %d、身長: %.1f、成績: %c\n", age, height, grade);
    return 0;
}
TEXT
年齢: 25、身長: 175.5、成績: A

幅と配置

% とフォーマット指定子の間に数値を入れると出力幅を制御できます:

C
#include <stdio.h>

int main(void) {
    int num = 42;
    printf("[%5d]\n", num);
    printf("[%-5d]\n", num);
    printf("[%05d]\n", num);
    printf("[%+5d]\n", num);
    return 0;
}
TEXT
[   42]
[42   ]
[00042]
[  +42]

浮動小数点の精度

C
#include <stdio.h>

int main(void) {
    double pi = 3.14159265358979;
    printf("デフォルト:  %f\n", pi);
    printf("2 桁: %.2f\n", pi);
    printf("6 桁: %.6f\n", pi);
    printf("8.2:      %8.2f\n", pi);
    return 0;
}
TEXT
デフォルト:  3.141593
2 桁: 3.14
6 桁: 3.141593
8.2:          3.14
💡 ヒント: %f のデフォルトは小数点以下 6 桁です。小数部分を完全に非表示にするには %.0f を使ってください。

scanf入力読み取り

scanf は「scan formatted」の略です。フォーマット文字列に従って標準入力からデータを読み取り、変数に格納します。

基本的な使い方

C
#include <stdio.h>

int main(void) {
    int age;
    float score;
    printf("年齢を入力してください: ");
    scanf("%d", &age);
    printf("得点を入力してください: ");
    scanf("%f", &score);
    printf("年齢: %d、得点: %.1f\n", age, score);
    return 0;
}
TEXT
年齢を入力してください: 20
得点を入力してください: 92.5
年齢: 20、得点: 92.5
⚠️ 注意: scanf の変数引数の前には &(アドレス演算子)を付ける必要があります。「このアドレスに値を格納せよ」と scanf に伝えるためです。& を忘れるのは初心者によくある間違いで——エラーにはなりませんがクラッシュします。

複数の値の読み取り

C
#include <stdio.h>

int main(void) {
    int a, b, c;
    printf("3 つの整数を入力(スペース区切り): ");
    scanf("%d %d %d", &a, &b, &c);
    printf("入力値: %d、%d、%d\n", a, b, c);
    return 0;
}
TEXT
3 つの整数を入力(スペース区切り): 10 20 30
入力値: 10、20、30

デフォルトでは、scanf は空白文字(スペース、改行、タブ)で異なる値を区切ります。

文字と文字列の読み取り

C
#include <stdio.h>

int main(void) {
    char ch;
    char name[20];
    printf("1 文字を入力: ");
    scanf(" %c", &ch);
    printf("名前を入力(スペースなし): ");
    scanf("%s", name);
    printf("文字: %c、名前: %s\n", ch, name);
    return 0;
}
⚠️ 注意: %c の前にスペースを入れる(" %c")と空白文字がスキップされます。そうしないと前の入力の改行が読み込まれてしまいます。%s は文字列を読み取りますが空白で止まります。name は配列名であり、すでにアドレスなので & は不要です。

scanfの戻り値

scanf は正常に読み取った変数の数を返します。この機能で入力の検証ができます:

C
#include <stdio.h>

int main(void) {
    int num;
    printf("整数を入力してください: ");
    int result = scanf("%d", &num);
    if (result == 1) {
        printf("読み取り成功: %d\n", num);
    } else {
        printf("無効な入力です!\n");
    }
    return 0;
}
TEXT
整数を入力してください: abc
無効な入力です!

getcharとputchar

getchar() はキーボードから 1 文字を読み取り、putchar() は画面に 1 文字を出力します。scanf("%c")printf("%c") よりシンプルで効率的です。

C
#include <stdio.h>

int main(void) {
    char ch;
    printf("1 文字を入力: ");
    ch = getchar();
    printf("入力された文字: ");
    putchar(ch);
    putchar('\n');
    return 0;
}
TEXT
1 文字を入力: X
入力された文字: X

1 行の読み取り

getchar() とループを組み合わせると、改行まで 1 行全体を読み取れます:

C
#include <stdio.h>

int main(void) {
    char ch;
    printf("1 行入力してください: ");
    while ((ch = getchar()) != '\n') {
        putchar(ch);
    }
    putchar('\n');
    return 0;
}
TEXT
1 行入力してください: Hello World!
Hello World!
💡 ヒント: while ((ch = getchar()) != '\n') は定番のイディオムです:まず ch に 1 文字を読み込み、それが改行かどうかをチェックします。代入を囲む外側の括弧は必須です。

バッファの問題

C言語の標準入力は行バッファリングを使います:ユーザーが Enter キーを押すまで、1 行のデータ全体がバッファに届いてプログラムが読み取れるようになります。これが原因で分かりにくい問題が起きることがあります。

問題:scanf %c が残った改行を読み取る

C
#include <stdio.h>

int main(void) {
    int num;
    char ch;
    printf("整数を入力: ");
    scanf("%d", &num);
    printf("文字を入力: ");
    scanf("%c", &ch);
    printf("整数=%d、文字=%d\n", num, ch);
    return 0;
}
TEXT
整数を入力: 42
文字を入力: 整数=42、文字=10

42 と入力して Enter を押すと、バッファには 42\n が含まれます。scanf("%d") は 42 を読み取り、scanf("%c") は残っている \n(ASCII コード 10)をすぐに読み取ってしまい、文字の入力を待ちません。

解決策

解決策 1:%c の前にスペースを追加(推奨)

C
scanf(" %c", &ch);

スペースはすべての空白文字(改行、スペース、タブ)をスキップします。

解決策 2:getchar() で残りを吸収

C
scanf("%d", &num);
getchar();
scanf("%c", &ch);

解決策 3:入力バッファをクリア

C
int c;
while ((c = getchar()) != '\n' && c != EOF) {}
⚠️ 注意: fflush(stdin) で入力バッファをクリアしないでください——標準 C言語では未定義動作です。一部のコンパイラはサポートしていますが、移植性がありません。

整数と文字の両方を読み取るプログラムで、バッファの残りを適切に処理します:

C
#include <stdio.h>

int main(void) {
    int age;
    char gender;
    printf("年齢を入力: ");
    scanf("%d", &age);
    printf("性別を入力(M/F): ");
    scanf(" %c", &gender);
    printf("年齢: %d、性別: %c\n", age, gender);
    return 0;
}
▶ 試してみよう
TEXT
年齢を入力: 25
性別を入力(M/F): M
年齢: 25、性別: M

getchar() で 1 文字ずつ読み取り、1 行中の文字数と数字の数を数えます:

C
#include <stdio.h>

int main(void) {
    char ch;
    int letters = 0;
    int digits = 0;
    printf("1 行入力してください: ");
    while ((ch = getchar()) != '\n') {
        if (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') {
            letters++;
        } else if (ch >= '0' && ch <= '9') {
            digits++;
        }
    }
    printf("文字数: %d、数字の数: %d\n", letters, digits);
    return 0;
}
▶ 試してみよう
TEXT
1 行入力してください: Hello 2024!
文字数: 5、数字の数: 4

putsとfputs

puts() は文字列を出力し、自動的に改行を追加します。printf よりシンプルで、プレーンテキスト出力に最適です:

C
#include <stdio.h>

int main(void) {
    puts("Hello, World!");
    puts("自動で改行されるので \\n は不要");
    return 0;
}
TEXT
Hello, World!
自動で改行されるので \n は不要
💡 ヒント: puts() はフォーマット文字列を解析する必要がないため、printf("%s\n", ...) より効率的です。フォーマットが不要な場合は puts を優先しましょう。

❓ よくある質問

Q なぜ scanf の変数には & を付けるのですか?
A scanf は値を格納する場所を知る必要があり、& は変数のアドレスを取得します。配列名だけが例外で、配列名はすでに先頭要素のアドレスだからです。
Q scanf("%c") が入力をスキップしました——何が起きたのですか?
A 前の入力の改行がバッファに残っているのが原因です。%c の前にスペースを追加してください:scanf(" %c", &ch) とすると空白文字がスキップされます。
Q printf と scanf のフォーマット指定子に大文字は使えますか?
A 一部は使えます。%d 小文字は int に対応し、大文字 %D は非標準です。ただし %x は小文字の 16 進(abcdef)を出力し、%X は大文字(ABCDEF)を出力します——これは有効です。
Q スペースを含む文字列を安全に読み取るにはどうすればいいですか?
A scanf("%s") は空白で止まります。fgets(name, sizeof(name), stdin) を使えば 1 行全体を読み取れ、スペースにも対応しより安全です。

📖 まとめ

📝 練習問題

  1. 円の半径を読み取り、printf%.2f フォーマットで面積と円周を出力するプログラムを書いてください
  2. getchar() で 1 行の入力を読み取り、大文字と小文字がそれぞれ何文字あるかを数えるプログラムを書いてください
  3. 整数を読み取り、10 進(%d)、16 進(%x)、8 進(%o)形式で出力するプログラムを書いてください
100%