int型やdouble型などの数値を文字列に変換する方法を紹介します。
snprintf関数で数値を文字列に変換する
C言語で数値を文字列に変換する場合にはsnprintf関数の利用が最適です。環境によっては同等の関数としてsprintf_sが利用できる場合もあります。
snprintfの第一引数に書き込み先の文字列のバッファ、第二引数にそのバッファのサイズを指定します。第三引数以降にはprintf関数と同等の書式文字列と各種実引数を指定します。
// #include <stdio.h> // snprintf, puts
int i = -99;
char buf[12];
snprintf(buf, 12, "%d", i);
puts(buf); // "-99"
変換指定子に%d
を指定することでint型の整数値の文字列化を実現することができます。%ld
を指定すればlong型、%f
を指定すればfloat型やdouble型の浮動小数点数を文字列変換することができます。詳しくは次項を参考にしてください。
double f = 3.141;
char buf[24];
snprintf(buf, 24, "%f", f);
puts(buf); // "3.141000"
snprintf(buf, 24, "%.2f", f);
puts(buf); // "3.14"
目次
- 変換指定子(long, float, short, char型からの変換)
- ゼロ埋め・左詰め・右詰めによる文字列変換
- 数値を16進数・8進数の文字列に変換する方法
- snprintf関数のバッファのサイズと注意点
- sprintf関数は使わないようにする
- itoa関数は使えない場合がある
変換指定子
snprintfはprintf関数と同等の変換指定子が利用できるため、long型("%ld"
)やchar("%c"
)による変換も可能です。
型名 | 変換指定子 | 備考 |
---|---|---|
char | %c | |
int | %d | 10進符号付き整数 |
unsigned int | %u | 10進符号無し整数 |
unsigned int | %o, %x | 8進数, 16進数 符号無し整数 |
long | %ld | long型のサイズが64bitの場合 |
float | %f | |
double | %f | %lfは不要 |
ゼロ埋め・左詰め・右詰めによる文字列変換
snprintf/sprintf関数でゼロ埋めや左詰め、右詰めを実現することも可能です。フォーマットの方法はprintf関数のものと共通です。
char s[5];
snprintf(s, 5, "%04d", 12); // "0012"(ゼロ埋め)
snprintf(s, 5, "%-4d", 12); // "12 "(左詰め)
snprintf(s, 5, "%4d", 12); // " 12"(右詰め)
参考:printf/sprintf関数でゼロ埋め・左詰め・右詰めを行う方法
数値を16進数・8進数の文字列に変換する方法
printf関数と同等のフォーマットが可能ですので、16進数・8進数表記による文字列化も行えます。
int i = 16;
char buf[20];
snprintf(buf, 20, "%#x", i);
puts(buf); // "0x10"(16進数)
snprintf(buf, 20, "%#o", i);
puts(buf); // "020" (8進数)
より具体的な方法やフォーマット方法については以下のページが参考になります。
参考:数値を 2進数 8進数 16進数 文字列に変換する方法【snprintf】
参考:数値を 2進数 8進数 16進数 形式で出力する方法【printf】
snprintf関数のバッファのサイズと注意点
文字列の書き込み先となる配列(char buf[]
)のサイズは、数値の桁数に応じて適切な値を設定しておく必要があります。十分に大きなサイズを確保しておくのが賢明です。
// long型の符号付き最小値を考慮した変換
long l = LONG_MIN; // LONG_MIN == -9223372036854775808
char buf[21]; // 21 == strlen("-9223372036854775808") + 1('\0')
snprintf(buf, 21, "%ld", l);
// unsigned int型の最大値を考慮した変換
unsigned int i = UINT_MAX; // UINT_MAX == 4294967295
char buf[11]; // 11 == strlen("4294967295") + 1('\0')
snprintf(buf, 11, "%u", i);
文字列の末尾に書き込まれる終端文字('\0'
)の分のサイズも考慮する必要があります。snprintfの第二引数に指定するサイズは終端文字を含んだ長さとなります。
char s[5];
snprintf(s, 5, "%d", 12345); // "1234"
sprintf関数は使わないようにする
「# snprintf関数で数値を文字列に変換する」で紹介したsnprintf関数の他に、sprintf関数も存在しますが、sprintfはバッファオーバーフローの危険性があるため、現在ではsnprintfやsprintf_sの利用が推奨されています。
以下はsprintf関数の正常な利用例です。
int i = 89;
char buf[3];
sprintf(buf, "%d", i); // buf == {'8', '9', '\0'}
以下はバッファオーバーランが発生した危険な処理の例です。
int i = 123;
char buffer_overflow = 9, buf[3];
sprintf(buf, "%d", i); // buf == {'1', '2', '3'}
printf("%s, %d", buf, buffer_overflow == '\0'); // "123, 1"
buf
配列に対して過剰に書き込まれた終端文字列'\0'
がbuffer_overflow
変数の値を上書きしてしまっていることが分かります。
このような問題が起きる恐れがあるため、sprintf関数を利用する際には、十分なバッファーサイズを確保して利用したり、安全な利用が想定できる場合にのみ注意して利用することが求められます。
itoa関数は使えない場合がある
itoa関数による同等の変換も可能ですが、itoa/_itoa関数は特定の環境でしか使えない非標準の関数です。移植性に問題があるため、利用はオススメはしません。同じことはsnprintf関数やsprintf関数でも実現できます。
char buf[3];
itoa(89, buf, 10); // buf == {'8', '9', '\0'}