sprintf関数
文字列操作6
文字列を数値に変換するには、atoi
関数やstrtol
関数を使用すると説明しました。
(文字を数値に変換参照)
では、その逆はどうすればよいのでしょうか。
実はC言語の標準関数ではこの機能を持った関数はありません。
コンパイラによっては「atoi」の逆である「itoa」という関数が存在することがありますが、常に使えるわけではないので使用は推奨されていません。
(Visual C++では_itoa
という名前で使用可能です)
これを実現するにはsprintf
関数、snprintf
関数、またはsprintf_s
関数、snprintf_s
関数を使用します。
これらは非常に強力な文字列操作関数で、strcat(文字列結合)やstrcpy(文字列コピー)などもこれで代用が可能です。
sprintf_s
関数、snprintf_s
関数はコンパイラによっては使用できません。
sprintf
関数はVisualStudio既定の設定では使用するとエラーとなります。
詳しくは_s系関数とエラー表示についてを参照してください。
sprintf、snprintf関数
-
int sprintf(
char *buffer,
const char *format [,
argument] ...
); -
文字列配列bufferに、書式指定文字列formatに従って変換した文字列を格納する。
戻り値は書き込まれた文字数。
エラーが発生した場合は負数を返す。
-
int snprintf(
char *buffer,
size_t count,
const char *format [,
argument] ...
); -
文字列配列bufferに、書式指定文字列formatに従って変換した文字列をcount文字分格納する。
戻り値は書き込まれた文字数。
エラーが発生した場合は負数を返す。
#include <stdio.h>
//文字列配列のサイズ
#define BUFFER 256
int main()
{
char buf1[BUFFER];
char buf2[BUFFER];
const char str1[] = "名前";
const char str2[] = "年齢";
const char str3[] = "身長";
const char name[] = "〇山×男";
int age = 20;
double height = 170.5;
sprintf(
buf1,
"%s: %s\n%s: %d\n%s: %.1f\n",
str1, name,
str2, age,
str3, height
);
snprintf(
buf2,
BUFFER,
"%s: %s\n%s: %d\n%s: %.1f\n",
str1, name,
str2, age,
str3, height
);
printf("%s\n", buf1);
printf("%s\n", buf2);
getchar();
}
名前: 〇山×男 年齢: 20 身長: 170.5 名前: 〇山×男 年齢: 20 身長: 170.5
これらの関数はprintf
関数と非常に近い動作をします。
書式指定文字列も同じものが使用できます。
printf
関数は結果の文字列を標準出力に出力しますが、sprintf
系の関数は結果の文字列を別のchar型配列に出力します。
sprintf
関数はコピー先配列のサイズの指定がなく、サイズが足りない場合にバッファオーバーランが発生するので使用は避けるべきです。
snprintf
関数は第二引数sizeOfBuffer
でコピー先配列のサイズを指定できます。
この値よりもコピーされる文字列のサイズが大きい場合、文字列は切り捨てられます。
この時必ず配列の終端にNULL文字が付加されるため、実際にコピーできる文字数は「sizeOfBuffer - 1」までとなります。
#include <stdio.h>
int main()
{
char buf1[5], buf2[10];
snprintf(buf1, sizeof(buf1), "ABCDEFG");
snprintf(buf2, sizeof(buf2), "ABCDEFG");
printf("%s\n", buf1);
printf("%s\n", buf2);
getchar();
}
ABCD ABCDEFG
sprintf_s、snprintf_s関数
-
int sprintf_s(
char *buffer,
size_t sizeOfBuffer,
const char *format,
...
); -
文字列配列bufferに、書式指定文字列formatに従って変換した文字列をsizeOfBuffer文字分格納する。
戻り値は書き込まれた文字数。
エラーが発生した場合は負数を返す。
-
int snprintf_s(
char *buffer,
size_t sizeOfBuffer,
const char *format,
...
); -
文字列配列bufferに、書式指定文字列formatに従って変換した文字列をsizeOfBuffer文字分格納する。
戻り値は書き込まれた文字数。
エラーが発生した場合は負数を返す。
snprintf_s
関数は上記のような定義ですが、当方のテスト環境にこの関数が使えるコンパイラがありません。
VisualStudioでは以下の_snprintf_s
関数ができるので、代わりに紹介します。
-
int _snprintf_s(
char *buffer,
size_t sizeOfBuffer,
size_t count,
const char *format [,
argument] ...
); -
文字列配列buffer(サイズはsizeOfBuffer)に、書式指定文字列formatに従って変換した文字列をcount文字分格納する。
戻り値は書き込まれた文字数。
エラーが発生した場合は負数を返す。
#include <stdio.h>
//文字列配列のサイズ
#define BUFFER 256
int main()
{
char buf1[BUFFER];
char buf2[BUFFER];
const char str1[] = "名前";
const char str2[] = "年齢";
const char str3[] = "身長";
const char name[] = "〇山×男";
int age = 20;
double height = 170.5;
sprintf_s(
buf1,
BUFFER,
"%s: %s\n%s: %d\n%s: %.1f\n",
str1, name,
str2, age,
str3, height
);
_snprintf_s(
buf2,
BUFFER,
BUFFER,
"%s: %s\n%s: %d\n%s: %.1f\n",
str1, name,
str2, age,
str3, height
);
printf("%s\n", buf1);
printf("%s\n", buf2);
getchar();
}
名前: 〇山×男 年齢: 20 身長: 170.5 名前: 〇山×男 年齢: 20 身長: 170.5
sprintf_s
関数はコピー先配列のサイズが足りずに文字列の切り捨てが発生するとエラーを発生させ、プログラムを停止します。
_snprintf_s
関数は第三引数count
でコピーする文字数を制限できます。
終端にNULL文字を付加するので「コピー先配列サイズ-1」を指定すると安全にコピーができます。
_TRUNCATE
という定数を指定すると同様の動作となります。
#include <stdio.h>
int main()
{
char buf1[5], buf2[5], buf3[5];
//エラー発生
//sprintf_s(buf1, sizeof(buf1), "ABCDEFG");
_snprintf_s(buf2, sizeof(buf2), sizeof(buf2) - 1, "ABCDEFG");
_snprintf_s(buf3, sizeof(buf3), _TRUNCATE, "ABCDEFG");
//printf("%s\n", buf1);
printf("%s\n", buf2);
printf("%s\n", buf3);
getchar();
}
ABCD ABCD
複数の文字列を結合したい場合はstrcat
関数よりもsprintf
系の関数のほうが簡単に書けるでしょう。
文字、文字列以外の変数を文字列に変換したい場合にも重宝する関数です。
ちなみに、double型変数のheight
を表示するための変換指定子を%.1f
としています。
これは小数点の第一位までを表示する、という指定になります。
例えば小数点第三位まで表示したいのならば%.3f
と記述します。
今までは%f
と、特に桁数の指定をしていませんでしたが、この場合は自動的に%.6f
を指定したことになります。
printf関数の書式指定文字列について詳しくはprintf関数を参照してください。