入力と出力
入力と出力はあなたとコンピュータの会話のようなものです——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% |
#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;
}
年齢: 25、身長: 175.5、成績: A
幅と配置
% とフォーマット指定子の間に数値を入れると出力幅を制御できます:
%5d:最小 5 文字幅、右揃え%-5d:最小 5 文字幅、左揃え%05d:5 桁になるまでゼロ埋め
#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;
}
[ 42]
[42 ]
[00042]
[ +42]
浮動小数点の精度
%.2f:小数点以下 2 桁%8.2f:全体で最低 8 文字幅、小数点以下 2 桁%-8.2f:左揃え版
#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;
}
デフォルト: 3.141593
2 桁: 3.14
6 桁: 3.141593
8.2: 3.14
%f のデフォルトは小数点以下 6 桁です。小数部分を完全に非表示にするには %.0f を使ってください。
scanf入力読み取り
scanf は「scan formatted」の略です。フォーマット文字列に従って標準入力からデータを読み取り、変数に格納します。
基本的な使い方
#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;
}
年齢を入力してください: 20
得点を入力してください: 92.5
年齢: 20、得点: 92.5
&(アドレス演算子)を付ける必要があります。「このアドレスに値を格納せよ」と scanf に伝えるためです。& を忘れるのは初心者によくある間違いで——エラーにはなりませんがクラッシュします。
複数の値の読み取り
#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;
}
3 つの整数を入力(スペース区切り): 10 20 30
入力値: 10、20、30
デフォルトでは、scanf は空白文字(スペース、改行、タブ)で異なる値を区切ります。
文字と文字列の読み取り
#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 は正常に読み取った変数の数を返します。この機能で入力の検証ができます:
#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;
}
整数を入力してください: abc
無効な入力です!
getcharとputchar
getchar() はキーボードから 1 文字を読み取り、putchar() は画面に 1 文字を出力します。scanf("%c") や printf("%c") よりシンプルで効率的です。
#include <stdio.h>
int main(void) {
char ch;
printf("1 文字を入力: ");
ch = getchar();
printf("入力された文字: ");
putchar(ch);
putchar('\n');
return 0;
}
1 文字を入力: X
入力された文字: X
1 行の読み取り
getchar() とループを組み合わせると、改行まで 1 行全体を読み取れます:
#include <stdio.h>
int main(void) {
char ch;
printf("1 行入力してください: ");
while ((ch = getchar()) != '\n') {
putchar(ch);
}
putchar('\n');
return 0;
}
1 行入力してください: Hello World!
Hello World!
while ((ch = getchar()) != '\n') は定番のイディオムです:まず ch に 1 文字を読み込み、それが改行かどうかをチェックします。代入を囲む外側の括弧は必須です。
バッファの問題
C言語の標準入力は行バッファリングを使います:ユーザーが Enter キーを押すまで、1 行のデータ全体がバッファに届いてプログラムが読み取れるようになります。これが原因で分かりにくい問題が起きることがあります。
問題:scanf %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;
}
整数を入力: 42
文字を入力: 整数=42、文字=10
42 と入力して Enter を押すと、バッファには 42\n が含まれます。scanf("%d") は 42 を読み取り、scanf("%c") は残っている \n(ASCII コード 10)をすぐに読み取ってしまい、文字の入力を待ちません。
解決策
解決策 1:%c の前にスペースを追加(推奨)
scanf(" %c", &ch);
スペースはすべての空白文字(改行、スペース、タブ)をスキップします。
解決策 2:getchar() で残りを吸収
scanf("%d", &num);
getchar();
scanf("%c", &ch);
解決策 3:入力バッファをクリア
int c;
while ((c = getchar()) != '\n' && c != EOF) {}
fflush(stdin) で入力バッファをクリアしないでください——標準 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;
}
年齢を入力: 25
性別を入力(M/F): M
年齢: 25、性別: M
例
getchar() で 1 文字ずつ読み取り、1 行中の文字数と数字の数を数えます:
#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;
}
1 行入力してください: Hello 2024!
文字数: 5、数字の数: 4
putsとfputs
puts() は文字列を出力し、自動的に改行を追加します。printf よりシンプルで、プレーンテキスト出力に最適です:
#include <stdio.h>
int main(void) {
puts("Hello, World!");
puts("自動で改行されるので \\n は不要");
return 0;
}
Hello, World!
自動で改行されるので \n は不要
puts() はフォーマット文字列を解析する必要がないため、printf("%s\n", ...) より効率的です。フォーマットが不要な場合は puts を優先しましょう。
❓ よくある質問
& を付けるのですか?& は変数のアドレスを取得します。配列名だけが例外で、配列名はすでに先頭要素のアドレスだからです。scanf(" %c", &ch) とすると空白文字がスキップされます。%d 小文字は int に対応し、大文字 %D は非標準です。ただし %x は小文字の 16 進(abcdef)を出力し、%X は大文字(ABCDEF)を出力します——これは有効です。scanf("%s") は空白で止まります。fgets(name, sizeof(name), stdin) を使えば 1 行全体を読み取れ、スペースにも対応しより安全です。📖 まとめ
printfはフォーマット指定子で出力を制御します:幅、精度、配置、パディングscanfでは変数の前に&が必要です。%cの前にスペースを入れると残った改行の読み取りを防げますgetchar/putcharは 1 文字の入出力に効率的な選択肢です- 行バッファリングにより scanf と getchar の呼び出し間で残りデータの問題が発生します
- scanf の戻り値で入力が成功したかどうかを検証できます
📝 練習問題
- 円の半径を読み取り、
printfの%.2fフォーマットで面積と円周を出力するプログラムを書いてください getchar()で 1 行の入力を読み取り、大文字と小文字がそれぞれ何文字あるかを数えるプログラムを書いてください- 整数を読み取り、10 進(
%d)、16 進(%x)、8 進(%o)形式で出力するプログラムを書いてください



