printf() の仕組みをきちんと理解する章。
05・06 では「とりあえず使う」形で登場したが、ここで正式に学ぶ。
C言語では、モニタ・キーボード・ファイルなどの入出力先をすべて「ファイル」として統一的に扱う。
画面への出力を特に標準出力(standard output)と呼ぶ。
標準出力に書き込む関数が printf() である。
printf() の基本構文printf("書式文字列", 値1, 値2, ...);
% で始まる部分が書式指定子printf("こんにちは¥n"); /* 文字列をそのまま表示 */
printf("合計は %d 点です¥n", 95); /* %d の位置に 95 が入る */
改行やタブなど「表示できない動作」を文字列の中に書くための特別な表記をエスケープシーケンスと呼ぶ。
| 表記 | 動作 | よく使う場面 |
|---|---|---|
¥n | 改行 | 出力の末尾にほぼ必ず使う |
¥t | タブ(横方向の空白) | 表形式の出力を揃えるとき |
¥¥ | \ を表示 | パスやファイル名の \ |
¥" | " を表示 | 文字列の中にダブルクォートを入れたいとき |
\ が「¥マーク(¥)」として表示されることがある。意味は同じ。
#include <stdio.h>
int main(void)
{
printf("お買い上げの¥"金額¥"は¥n¥t¥¥13,280- です¥n");
return 0;
}
お買い上げの"金額"は \13,280- です
% に1文字を組み合わせたもので、どの型の値をどう表示するかを指定する。
| 書式指定子 | 表示する型 | 語源 |
|---|---|---|
%d | int(10進数) | decimal(10進) |
%x / %X | int(16進数・小文字/大文字) | hexadecimal |
%o | int(8進数) | octal(8進) |
%c | char(1文字) | character |
%s | 文字列 | string |
%f | double / float(実数) | float |
%.2f | double / float(小数点以下2桁) | — |
#include <stdio.h>
int main(void)
{
int num = 100;
printf("10進数 = %d¥n", num);
printf(" 8進数 = %o¥n", num);
printf("16進数 = %x¥n", num); /* 小文字 */
printf("16進数 = %X¥n", num); /* 大文字 */
num = 0x61; /* 10進数で 97 = 文字 'a' */
printf("10進: %d, 16進: %x, 文字: %c¥n", num, num, num);
return 0;
}
10進数 = 100 8進数 = 144 16進数 = 64 16進数 = 64 10進: 97, 16進: 61, 文字: a
| 書式 | 意味 | 出力(値が 32 の場合) |
|---|---|---|
%5d | 幅5・右寄せ | [△△△32] |
%-5d | 幅5・左寄せ | [32△△△] |
%05d | 幅5・ゼロ埋め | [00032] |
%7s | 幅7・右寄せ(文字列) | [△△△moji] |
%-7s | 幅7・左寄せ(文字列) | [moji△△△] |
%6.4s | 先頭4文字を幅6で右寄せ | [△△ELEP] |
#include <stdio.h>
int main(void)
{
printf("[%5d]¥n", 32);
printf("[%-5d]¥n", 32);
printf("[%05d]¥n", 32);
printf("[%s]¥n", "moji");
printf("[%7s]¥n", "moji");
printf("[%-7s]¥n", "moji");
printf("[%6.4s]¥n", "ELEPHANT");
return 0;
}
[△△△32] [32△△△] [00032] [moji] [△△△moji] [moji△△△] [△△ELEP]
次のコードの ? に正しい書式指定子を入れて、実行結果が一致するようにせよ。
#include <stdio.h>
int main(void)
{
int a = 123;
double b = 3.14;
char c = 'Z';
printf("整数 : %?¥n", a);
printf("実数 : %?¥n", b);
printf("文字 : %?¥n", c);
return 0;
}
期待される実行結果:
整数 : 123 実数 : 3.140000 文字 : Z
%d(int)・%f(double)・%c(char)
printf("整数 : %d¥n", a);
printf("実数 : %f¥n", b);
printf("文字 : %c¥n", c);
次のコードを実行する前に、出力結果を紙またはノートに書いてみよう。
その後、実際に打ち込んで実行し、予測と一致するか確認せよ。
#include <stdio.h>
int main(void)
{
printf("[%6d]¥n", 42);
printf("[%-6d]¥n", 42);
printf("[%06d]¥n", 42);
printf("[%6d]¥n", -42);
return 0;
}
[△△△△42] [42△△△△] [000042] [△△△-42]
マイナスの場合、符号も1文字分を幅に含む。-42 は3文字なので残り3文字分(△△△)が入る。
次の実行結果と一致するように、printf を使って出力するプログラムを作れ。
幅指定(%Nd や %-Ns)を使って列を揃えること。
期待される実行結果:
名前 点数 評価 ---------- ---- ---- Alice 92 A Bob 75 B Charlie 61 C
#include <stdio.h>
int main(void)
{
/* ここに printf を書いて上の表を出力せよ */
return 0;
}
#include <stdio.h>
int main(void)
{
printf("%-10s %4s %4s¥n", "名前", "点数", "評価");
printf("---------- ---- ----¥n");
printf("%-10s %4d %4s¥n", "Alice", 92, "A");
printf("%-10s %4d %4s¥n", "Bob", 75, "B");
printf("%-10s %4d %4s¥n", "Charlie", 61, "C");
return 0;
}
名前列は左寄せ(%-10s)、点数列は右寄せ(%4d)にすると自然に揃う。
次のコードを打ち込んで実行し、同じ整数値が書式指定子によってどう見え方が変わるかを確認せよ。
実行後、n の値を 0x41・48・10 に変えて試してみよう。
#include <stdio.h>
int main(void)
{
int n = 65; /* ← この値を変えて試そう */
printf("10進数 : %d¥n", n);
printf("16進数 : %x¥n", n);
printf(" 8進数 : %o¥n", n);
printf(" 文字 : %c¥n", n);
return 0;
}
n = 65 のときの実行結果:
10進数 : 65 16進数 : 41 8進数 : 101 文字 : A
n = 48(文字 '0' の ASCII コード)
10進数 : 48 16進数 : 30 8進数 : 60 文字 : 0
n = 10(改行文字 '¥n' の ASCII コード)
10進数 : 10 16進数 : a 8進数 : 12 文字 :
n = 10 のとき、%c は改行文字を出力するため「文字 :」の後に改行が入る。
Q1. 改行を表すエスケープシーケンスはどれか。
正解:ウ
¥n が改行。¥t はタブ、¥r はキャリッジリターン(行頭に戻る)。
Q2. printf("[%05d]¥n", 7); の出力として正しいものはどれか。
正解:イ
%05d は「幅5・ゼロ埋め」。7 は1桁なので残り4桁をゼロで埋めて 00007 になる。
Q3. printf("[%6.3s]¥n", "tiger"); の出力として正しいものはどれか。
正解:ウ
%6.3s は先頭3文字を取り出し、幅6で右寄せ。"tiger" → "tig" → [△△△tig]。
Q4. 次のコードの出力として正しいものはどれか。
#include <stdio.h>
int main(void)
{
int n = 65;
printf("%d %x %c¥n", n, n, n);
return 0;
}
正解:ア
同じ値 65 を %d(10進)→ 65、%x(16進)→ 41、%c(文字)→ A と異なる形式で表示する。
| 項目 | 内容 |
|---|---|
printf() | 標準出力(画面)に文字・数値を表示する関数 |
| エスケープシーケンス | ¥n(改行)・¥t(タブ)・¥¥・¥" |
| 書式指定子 | %d %f %c %s %x %o |
| 幅指定 | %5d(右寄せ)・%-5d(左寄せ)・%05d(ゼロ埋め) |