カウンタがうまく回ってなかった。。。
さて、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だけだとコピー元の長さによってフォーマットが長くなってしまう。

とこんなことをいろいろ調べて今日も帰りが遅くなってしまった。。。

Updated:

Comments