sprintf

カウンタがうまく回ってなかった。。。
さて、C言語で文字列のコピーしたいとき、しかもstd::stringじゃなくてchar*で。
これが悩むんだけど、標準ライブラリを使おうとすると
・strcpy
・strncpy
・sprintf/snprintf
この3つになる。
けど、この3つが結構くせ者なのね。


まず、strcpy。たぶん一番単純。

char *strcpy(char *dest, const char *src);

srcからdestに文字列をコピーするだけなんだけど、srcがdestより大きい場合ってのが
問題。普通にそのままコピーするからdestの範囲じゃないところまで書き込んじゃう。
いわゆるバッファオーバーフロー。
だから、サイズチェックは必須になる。忘れやすいから使わない方がいい。
次に、strncpy。ちょっとましになった版。

char *strncpy(char *dest, const char *src, size_t n);

さっきのstrcpyにサイズを示すnが入っていて、一応上のバグはつぶされてる。
けど、この関数に仕様が微妙で
・nを超える文字数がコピーされることはない。
・src の長さが n よりも少ない場合は、 dest の残りは NUL 文字で埋められる。
・srcがnよりも大きい場合、終端文字(NULL)文字は挿入しない
ということでsrcがn文字より大きかった場合、終わりがない文字列に成っちゃうのね。
だから

strncpy(dest, src, sizeof(dest)-1);

とかで確実に終端文字が入るようにしないといけない。
まあ、これはこれでsrcの長さがnより小さかったらNULを入れる処理が入るから、
長いバッファを使ったときにパフォーマンスがわるくなっちゃう。
最後にsprintf。

int sprintf(char *str, const char *format, ...);

けど、これはstrcpyと同じ問題を抱えてるからこっちを使おう。

int snprintf(char *str, size_t size, const char *format, ...);

printfみたくフォーマット指定で文字列を書き込める関数。
フォーマット指定の仕方できっちりした文字列コピーが可能。

sprintf(buf, "%.*s", sizeof(buf)-1, "long-string");

ここでポイントが%.*sと精度指定すること。そうしないと
%*sだけだとコピー元の長さによってフォーマットが長くなってしまう。
とこんなことをいろいろ調べて今日も帰りが遅くなってしまった。。。

コメント