C言語で画面に値を表示するにはprintf
を使います。
本記事ではよく使う書式指定子を一覧で整理し、基本の使い方から桁幅・精度の指定、よくある間違いまで、初心者の方にも分かりやすく実例付きで解説します。
整数や小数、文字列、アドレスの表示方法を中心に、実行結果も確認しながら理解を深めていきます。
C言語のprintfと書式指定子の基本
printfの基本構文と使い方(例)
printf
はフォーマット文字列と複数の引数を受け取り、整形された文字列を標準出力に表示します。
フォーマット文字列内の%
で始まる記号が書式指定子です。
使う前に#include <stdio.h>
を忘れないでください。
#include <stdio.h>
int main(void) {
// 文字列の表示
printf("Hello, printf!\n");
// 整数の表示(%d)と計算結果の埋め込み
int a = 2, b = 3;
printf("%d + %d = %d\n", a, b, a + b);
// 浮動小数点の表示(%f)と精度指定(%.2f)
double pi = 3.1415926535;
printf("pi(標準) = %f\n", pi); // デフォルトは小数点以下6桁
printf("pi(小数2桁) = %.2f\n", pi); // 四捨五入されます
// printfは出力した文字数を返す
int count = printf("Count me!");
printf("\n直前のprintfが出力した文字数 = %d\n", count);
return 0;
}
Hello, printf!
2 + 3 = 5
pi(標準) = 3.141593
pi(小数2桁) = 3.14
Count me!
直前のprintfが出力した文字数 = 9
改行文字の\n
を入れると行が区切られて見やすくなります。
行末に改行が無いと、コンソールによってはプロンプトと同じ行に続いて表示されることがあります。
書式指定子(%)の考え方
書式指定子は値の型に合わせて選ぶのが大原則です。
一般形は次の通りです。
%[フラグ][桁幅][.精度][長さ]変換
- フラグの例:
-
(左寄せ),0
(ゼロ埋め) など - 桁幅: フィールドの最小幅(例:
%5d
) - 精度: 小数点以下や最大文字数(例:
%.2f
,%.3s
) - 長さ: 値のサイズ(例:
l
,ll
,z
) - 変換: 最後の1文字が種類(例:
d
,f
,s
)
型と変換の対応が正しくないと未定義動作になります。
例えばunsigned int
を%d
で出力するのは危険です。
printf書式指定子の一覧(基本の使い方と例)
以下は基本でよく使う指定子の一覧です。
括弧内は代表的な型です。
種別 | 書式 | 意味 | 例 | 備考 |
---|---|---|---|---|
整数 | %d, %i | 符号付き10進(int) | printf("%d", -42) | %d と%i はprintfでは同じ |
整数 | %u | 符号なし10進(unsigned int) | printf("%u", 3000000000u) | 符号なしで表示 |
整数 | %x, %X | 16進(unsigned int) | printf("%x", 255) →ff | %X は大文字(FF) |
整数 | %o | 8進(unsigned int) | printf("%o", 255) →377 | |
浮動小数 | %f | 固定小数(double) | printf("%f", 3.14) | 既定は小数6桁 |
浮動小数 | %e, %E | 指数表記(double) | printf("%e", 3.14) | %E でE表記 |
浮動小数 | %g, %G | %fか%eを自動選択 | printf("%g", 123456.0) | 余分な0を抑制 |
文字 | %c | 1文字(intとして渡す) | printf("%c", 'A') | |
文字列 | %s | 文字列(const char*) | printf("%s", "C") | 末尾の\0 まで |
アドレス | %p | ポインタ(void*) | printf("%p",(void*)&x) | 実装依存の表示 |
%自体 | %% | %そのもの | printf("%%") | 引数不要 |
長さ修飾子の例: %ld
(long), %lld
(long long), %zu
(size_t), %Lf
(long double) など。
必要に応じて使います。
整数を表示する(%d, %i, %u, %x, %o)
整数の基本は%d
ですが、値が符号なしなら%u
を使うのが正しいです。
16進や8進での表示はデバッグで便利です。
#include <stdio.h>
int main(void) {
int n = -42;
unsigned int u = 3000000000u; // 符号なしの大きな値(32bit環境でも収まる範囲)
int m = 255;
// 符号付きと符号なしの違い
printf("n を10進(符号付き) : %d\n", n);
printf("u を10進(符号なし) : %u\n", u);
// 同じ数値を異なる基数で
printf("m を10進 : %d\n", m);
printf("m を16進(小文字) : %x\n", m);
printf("m を16進(大文字) : %X\n", m);
printf("m を8進 : %o\n", m);
// 注意: 型を合わせる。%uにintをそのまま渡さない
printf("n を符号なしに解釈 : %u\n", (unsigned int)n); // キャストして対応
return 0;
}
n を10進(符号付き) : -42
u を10進(符号なし) : 3000000000
m を10進 : 255
m を16進(小文字) : ff
m を16進(大文字) : FF
m を8進 : 377
n を符号なしに解釈 : 4294967254
先頭に0x
や0
を付けたい場合はフラグ#
を使います(例: %#x
→0xff
)。
浮動小数点を表示する(%f, %e, %g)
浮動小数は通常%f
を使います。
指数表記なら%e
、%g
は%f
と%e
を状況に応じて選んでくれます。
#include <stdio.h>
int main(void) {
double x = 12345.6789;
double y = 0.000012345;
double z = 1000000.0;
printf("x を%%fで表示 : %f\n", x);
printf("x を%%eで表示 : %e\n", x);
printf("x を%%gで表示 : %g\n", x);
printf("y を%%fで表示 : %f\n", y);
printf("y を%%eで表示 : %e\n", y);
printf("y を%%gで表示 : %g\n", y);
printf("z を%%gで表示 : %g\n", z); // 大きい値では指数表記になりやすい
// 精度の指定
printf("x を小数3桁(%.3f) : %.3f\n", x, x);
return 0;
}
x を%fで表示 : 12345.678900
x を%eで表示 : 1.234568e+04
x を%gで表示 : 12345.7
y を%fで表示 : 0.000012
y を%eで表示 : 1.234500e-05
y を%gで表示 : 1.2345e-05
z を%gで表示 : 1e+06
x を小数3桁(%.3f) : 12345.679
floatは可変長引数でdoubleに拡張されるため、%f
が受け取るのは実質doubleです。
long double
を表示したい場合は%Lf
を使います。
文字と文字列(%c, %s)
%c
は1文字、%s
は終端が\0
の文字列を表示します。
#include <stdio.h>
int main(void) {
char ch = 'A';
const char *lang = "C language";
printf("1文字: %c\n", ch);
printf("文字列: %s\n", lang);
// %sで部分表示(最大文字数は精度で指定)
printf("先頭3文字: %.3s\n", lang);
return 0;
}
1文字: A
文字列: C language
先頭3文字: C l
UTF-8などマルチバイト文字列を%.3s
で切り詰めると、文字の途中で分割され文字化けの原因になります。
日本語を安全に扱うにはワイド文字や専用ライブラリの検討が必要です。
アドレスを表示する(%p)
%p
はポインタ値を出力します。
引数はvoid*
を受け取る仕様なのでキャストして渡すのが無難です。
#include <stdio.h>
int main(void) {
int x = 100;
int *px = &x;
void *pv = NULL;
printf("xのアドレス: %p\n", (void*)px);
printf("NULLポインタ: %p\n", pv);
return 0;
}
xのアドレス: 0x7ffd12a3b4c8
NULLポインタ: (nil)
パーセント記号を表示する(%%)
%
そのものを出したい場合は%%と書きます。
引数は不要です。
#include <stdio.h>
int main(void) {
int progress = 80;
printf("進捗: %d%% 完了\n", progress);
return 0;
}
進捗: 80% 完了
桁幅・精度・整列の指定(初心者向け)
桁幅を指定する(%5d)
桁幅は最低限確保する表示幅です。
足りない分は空白で埋められ、既定では右寄せになります。
#include <stdio.h>
int main(void) {
int a = 7, b = 123, c = -45;
// '|'で枠を作って空白を可視化
printf("|%5d|%5d|%5d|\n", a, b, c);
// 幅より桁数が多い場合は切り捨てず、幅が自動的に広がります
int big = 1234567;
printf("|%5d|\n", big);
return 0;
}
| 7| 123| -45|
|1234567|
桁幅は最小値であり最大値ではない点に注意してください。
小数点以下の桁数を指定する(%.2f)
%.nf
の形で小数点以下n桁を指定できます。
指定桁で四捨五入されます。
#include <stdio.h>
int main(void) {
double v1 = 1.2345;
double v2 = 1.2355;
printf("%.2f\n", v1); // 1.23
printf("%.2f\n", v2); // 1.24
// 幅と精度の併用(幅8, 小数3桁)
printf("|%8.3f|\n", v1);
return 0;
}
1.23
1.24
| 1.234|
文字列の最大文字数を指定する(%.3s)
%s
では%.ns
で最大文字数を指定します。
長い文字列の見出しなどを切り詰めたい時に便利です。
#include <stdio.h>
int main(void) {
const char *title = "printf format";
printf("|%.3s|\n", title); // 先頭3文字だけ
printf("|%8.3s|\n", title); // 幅8で右寄せ、かつ最大3文字
return 0;
}
|pri|
| pri|
日本語などマルチバイトでは文字途中で切れて文字化けの恐れがあります。
UTF-8を扱う場合は注意しましょう。
左寄せ(-)とゼロ埋め(0)
フラグ-
で左寄せ、0
でゼロ埋めを指定できます。
-と0を同時に指定した場合は-が優先され、ゼロ埋めは無効になります。
#include <stdio.h>
int main(void) {
int n = 42;
int neg = -42;
const char *s = "C";
// 左寄せ
printf("|%-5d|\n", n);
// ゼロ埋め(数値のみ有効)
printf("|%05d|\n", n);
// 負数のゼロ埋め(符号の後ろが0で埋まる)
printf("|%05d|\n", neg);
// 文字列に0フラグを付けても効果はありません
printf("|%05s|\n", s); // 0は無視され幅指定のみが有効
return 0;
}
|42 |
|00042|
|-0042|
| C|
0フラグは数値の表示でのみ意味があります。
文字列や%c%c%c%c%sでは無視されます。
よくある間違いと注意点
書式指定子と変数の型を合わせる
型と書式が合わないと未定義動作になり、間違った値が表示されたりクラッシュしたりします。
悪い例(未定義動作):
#include <stdio.h>
int main(void) {
unsigned int u = 10;
// 誤り: %dは符号付きintを想定。unsignedを渡すべきではない
printf("%d\n", u); // 未定義動作
return 0;
}
正しい例(型に合わせる):
#include <stdio.h>
#include <stddef.h> // size_t
#include <stdint.h> // 標準幅整数(必要なら)
#include <inttypes.h> // PRId32などのマクロ(必要なら)
int main(void) {
long l = 1234567890L;
long long ll = 1234567890123LL;
size_t sz = 42;
unsigned long ul = 4000000000UL;
printf("long : %ld\n", l);
printf("long long : %lld\n", ll);
printf("size_t : %zu\n", sz);
printf("unsigned long: %lu\n", ul);
// 固定幅整数を安全に(必要な場合)
int32_t i32 = -100;
printf("int32_t : %" PRId32 "\n", i32);
return 0;
}
long : 1234567890
long long : 1234567890123
size_t : 42
unsigned long: 4000000000
int32_t : -100
要点:
int
は%d
、unsigned int
は%u
、long
は%ld
、long long
は%lld
。size_t
は%zu
、ptrdiff_t
は%td
。double
は%f
、long double
は%Lf
。
引数の数と順番を間違えない
プレースホルダの数と順番に合わせて引数を渡します。
足りない・順番違いも未定義動作です。
#include <stdio.h>
int main(void) {
int a = 10, b = 20;
// 誤り: %dが2つあるのに引数が1つ
// printf("%d %d\n", a); // 未定義動作
// 誤り: 順番を取り違え
// printf("%d %f\n", 3.14, a); // 未定義動作
// 正しい
printf("%d %d\n", a, b);
printf("%d %.2f\n", a, 3.14);
return 0;
}
10 20
10 3.14
改行(\n)を入れて見やすくする
行末の改行を忘れると表示が詰まりやすいです。
標準出力は行バッファリングされることがあり、改行でフラッシュされる環境もあります。
メッセージの区切りには\n
を付けましょう。
#include <stdio.h>
int main(void) {
printf("処理中..."); // 改行なし
// 何か重い処理があると仮定
printf("完了\n"); // 改行ありで行を区切る
return 0;
}
処理中...完了
%sにNULLや未初期化のポインタを渡さない
%sにNULLポインタを渡すとクラッシュの原因になります。
常に有効なconst char*
を渡してください。
#include <stdio.h>
int main(void) {
const char *p = NULL;
// 誤り: pはNULL
// printf("%s\n", p); // 実行時エラーになる可能性
// 正しい: 有効な文字列
p = "safe";
printf("%s\n", p);
return 0;
}
safe
未初期化ポインタも同様に危険です。
必ず初期化してから使いましょう。
まとめ
printfの書式指定子は「型に合わせて選ぶ」「桁幅・精度・整列を使い分ける」の2点を押さえると実務でも迷いません。
整数なら%d/%u/%x
、浮動小数なら%f/%e/%g
、文字と文字列は%c/%s
、アドレスは%p
、パーセントは%%
と覚え、必要に応じて-
や0
、桁幅や精度を組み合わせます。
さらに長さ修飾子(l
, ll
, z
など)で型に厳密に合わせると安全です。
最後に、型不一致や引数不足は未定義動作という基本ルールを忘れず、出力には適切な改行を入れて読みやすく整えましょう。