編集:例のソースを追加しました。
この例 :
char source[MAX] = "123456789";
char source1[MAX] = "123456789";
char destination[MAX] = "abcdefg";
char destination1[MAX] = "abcdefg";
char *return_string;
int index = 5;
/* This is how strcpy works */
printf("destination is originally = '%s'\n", destination);
return_string = strcpy(destination, source);
printf("after strcpy, dest becomes '%s'\n\n", destination);
/* This is how strncpy works */
printf( "destination1 is originally = '%s'\n", destination1 );
return_string = strncpy( destination1, source1, index );
printf( "After strncpy, destination1 becomes '%s'\n", destination1 );
この出力を生成したもの:
宛先は元々= 'abcdefg' strcpyの後、宛先は '123456789'になります destination1 is
だから誰がこの効果を望んでいるのだろうと思う。紛らわしいようです。このプログラムは、基本的に誰かの名前(たとえば、Tom Brokaw)をTom Bro763でコピーできると思います。
使用する利点は何ですかstrncpy()
overstrcpy()
?
strncpy
は、バッファオーバーフローに対処するために、長さを指定することを要求します。 strcpy
は末尾の\0
に依存しますが、常に発生するとは限りません。
第二に、7文字の文字列で5文字のみをコピーすることを選択した理由は私にはわかりませんが、予想される動作を生み出しています。最初のn
文字のみをコピーします。n
は3番目の引数です。
n
関数はすべて、バッファオーバーフローに対する防御コーディングとして使用されます。 strcpy
などの古い関数の代わりに使用してください。
strncpy()
関数は、非常に特定の問題を念頭に置いて設計されました。元のUNIXディレクトリエントリの方法で格納された文字列を操作します。これらは固定サイズの配列を使用し、nul-terminatorはファイル名が配列より短い場合にのみ使用されました。
これが、strncpy()
の2つの奇妙な点の背後にあるものです。
「より安全なstrcpy()
」の場合、次のようにstrncat()
を使用することをお勧めします。
if (dest_size > 0)
{
dest[0] = '\0';
strncat(dest, source, dest_size - 1);
}
それは常に結果を無効にし、必要以上にコピーすることはありません。
私はstrncpy
の背後にある意図を知っていますが、それは本当に良い機能ではありません。両方を避けてください。 レイモンド・チェンが説明する 。
個人的には、nullで終わる文字列を扱う場合は、
strncpy
とそのすべての友人を避けるだけです。名前の「str」にもかかわらず、これらの関数はヌル終了文字列を生成しません。 nullで終わる文字列を生の文字バッファに変換します。 2番目のバッファが間違っているため、ヌル終了文字列が予想される場所でそれらを使用します。ソースが長すぎる場合、適切なヌル終端を取得できないだけでなく、ソースが短い場合、不要なヌルパディングが発生します。
なぜstrncpyは安全ではないのですか? も参照してください。
strncpyはstrcpyより安全ではありません。あるタイプのバグを別のタイプのバグと交換するだけです。 Cでは、C文字列を処理する場合、バッファのサイズを知る必要がありますが、回避する方法はありません。 strncpyは、他の人が言及したディレクトリに対して正当化されましたが、それ以外の場合は使用しないでください。
あなたが探しているのは、常に文字列を0で終了し、バッファを初期化する関数strlcpy()
です。また、オーバーフローを検出することもできます。唯一の問題は、(本当に)移植性がなく、一部のシステム(BSD、Solaris)にのみ存在することです。この関数の問題は、 http://en.wikipedia.org/wiki/Strlcpy の議論でわかるように、ワームの別の缶を開くことです。
私の個人的な意見では、strncpy()
やstrcpy()
よりもはるかに便利です。パフォーマンスが向上し、snprintf()
の優れたコンパニオンです。それを持たないプラットフォームの場合、実装は比較的簡単です。 (アプリケーションの開発段階では、これら2つの関数(snprintf()
およびstrlcpy()
)を、バッファオーバーフローまたは切り捨てでプログラムを残酷に中止するトラップバージョンに置き換えます。これにより、最悪の犯罪者をすばやくキャッチできます。特に、他の人のコードベースで作業している場合。
編集:strlcpy()
は簡単に実装できます:
size_t strlcpy(char *dst, const char *src, size_t dstsize)
{
size_t len = strlen(src);
if(dstsize) {
size_t bl = (len < dstsize-1 ? len : dstsize-1);
((char*)memcpy(dst, src, bl))[bl] = 0;
}
return len;
}
strncpy()
関数の方が安全です。宛先バッファが受け入れることができる最大長を渡す必要があります。そうしないと、ソース文字列が正しく0で終了しない可能性があります。その場合、strcpy()
関数は宛先にさらに文字を書き込み、宛先バッファーの後のメモリにあるものをすべて破損する可能性があります。これは多くのエクスプロイトで使用されるバッファオーバーランの問題です
また、read()
のようなPOSIX API関数の場合、終端の0をバッファーに入れず、読み取ったバイト数を返すため、手動で0を入れるか、strncpy()
を使用してコピーします。
サンプルコードでは、index
は実際にはインデックスではなく、count
です。ソースからコピー先にコピーする文字数最大を示します。ソースの最初のnバイトの間にnullバイトがない場合、destinationに配置された文字列はnullで終了しません
strncpyは、宛先のサイズが小さい場合でも、宛先のサイズを「\ 0」でいっぱいにします。..
マンページ:
Srcの長さがnより小さい場合、strncpy()はdestの残りにヌルバイトを埋め込みます。
残りだけでなく...この後、n文字に達するまで。したがって、オーバーフローが発生します...(manページの実装を参照)
これは、元の文字列の一部のみを宛先にコピーする必要がある他の多くのシナリオで使用できます。 strncpy()を使用すると、strcpy()とは対照的に、元の文字列の限られた部分をコピーできます。あなたが書いたコードは publib.boulder.ibm.com から来ていると思います。