6

strcpy と strncpy の違い/欠点を理解しようとしています。誰か助けてください:

void main()
{
char src[] = "this is a long string";
char dest[5];

strcpy(dest,src) ;
printf("%s \n", dest);
printf("%s \n", src);

}

出力は次のとおりです。

this is a long string 
a long string 

質問: ソース文字列がどのように変更されたのかわかりません。説明によると、strcpy は '\0' に遭遇するまでコピーし続ける必要があります。

説明してください。

4

7 に答える 7

11

簡単な答えは、(その strcpy() 呼び出しで) システムの仕様の範囲外で何かを行ったため、未定義の動作に当然苦しんでいるということです。

より難しい答えは、システムの具体的なメモリ レイアウトと、strcpy() が内部でどのように機能するかを調べることです。おそらく次のようになります。

     N+28 "g0PP"
     N+24 "trin"
     N+20 "ng s"
     N+16 "a lo"
     N+12 " is "
src  N+08 "this"
     N+04 "DPPP"
dest N+00 "DDDD"

文字Dは dest のバイトを表し、文字Pはパディング バイト、文字は0文字列ターミネータとして使用される ASCII NUL 文字です。

strcpy(dest,src) はメモリの内容をいくらか変更します (オーバーラップするメモリ領域を正しく処理すると仮定します):

     N+28 "g0PP"
     N+24 "trin"
     N+20 "g0 s"
     N+16 "trin"
     N+12 "ng s"
src  N+08 "a lo"
     N+04 " is "
dest N+00 "this"

つまり、dest は完全な文字列「this is a long string」(オーバーフローしたメモリをカウントする場合) を「含む」ようになりましたが、src は完全に異なる NUL で終了する文字列「a long string」を含むようになりました。

于 2009-10-21T16:00:42.230 に答える
7

これはバッファ オーバーフローであり、未定義の動作です。

あなたの場合、コンパイラがメモリdestsrc順番に配置したようです。からsrcにコピーするとdest、 の末尾を越えてコピーが続行され、destの一部が上書きされますsrc

于 2009-10-21T15:57:29.813 に答える
1

文字列が正確に隣接している可能性が高いです。したがって、あなたの場合、この写真があるかもしれません

dst | | | | | | | |ソース | | | | | | | | | | |

書き始めると、src のフィールドが上書きされます。

しかし、あなたは確かにそれに頼ることはできません. あなたが持っているものはすべて未定義の動作である可能性があります。そのため、別のコンピューターで別の時間が発生したり、他のオプションが発生したりする可能性があります。

よろしく フリードリヒ

于 2009-10-21T15:58:22.203 に答える
1

コードが原因でバッファ オーバーフローが発生しました。dest にコピーすると、保持できる文字数を超えています。追加の文字は、あなたの場合、src が指していたスタック上の別の場所に書き込まれました。

関数を使用する必要がありstrncpy()ます。

于 2009-10-21T16:01:36.830 に答える
1

追加の注意として、strncpy関数は、バッファ オーバーラン保護を使用してコピーを実行する必要がある場合に使用する適切な関数ではないことに注意してください。この機能はその目的を意図したものではなく、その目的を意図したものではありません。strncpy古いバージョンの UNIX の非常に特定のファイルシステム内で非常にアプリケーション固有の文字列のコピーを実行するために、かなり前に作成された関数です。残念なことに、ライブラリの作成者は、strncpy非常に限定的で特定の目的に使用するために、一般的な響きの名前を「ハイジャック」することに成功しました。その後、下位互換性のために保持されました。strncpyそして今、1、2 世代のプログラマーが、その名前だけに基づいて の目的を推測し、その結果、それを不適切に使用しています。実際には、strncpy意味のある用途はほとんど、またはまったくありません。

C 標準ライブラリ (少なくともその C89/90 バージョン) は、バッファ オーバーラン保護を備えた文字列コピー機能を提供しません。このような保護されたコピーを実行するには、strlcpystrcpy_sなどのプラットフォーム固有の関数を使用するか、自分で作成する必要があります。

PS StackOverflowのこのスレッドstrncpyには、開発された本当の目的についての良い議論が含まれています。UNIX ファイル システムでの役割の正確な説明については、この投稿を参照してください。また、どのようにして生まれたかについての良い記事については、こちらstrncpyを参照してください。

繰り返しstrncpyますが、まったく異なる種類の文字列 (固定長文字列) をコピーする関数です。従来の C スタイルのヌル終了文字列で使用することさえ意図されていません。

于 2009-10-21T17:34:08.750 に答える
0

私があなたの質問を誤解しているか、あなたが strcpy を誤解しています:

質問: ソース文字列がどのように変更されたのかわかりません。説明によると、strcpy は '\0' に遭遇するまでコピーし続ける必要があります。

文字の表示に基づいて、 strcpy が dest の終わりに達したときに dest へのコピーを停止することを期待しているように思えます\0。これはそれがすることではありません。strcpy は、文字で区切られたソース文字列の末尾に到達するまで、コピー先にコピーします\0。コピーに十分なメモリが割り当てられていることを前提としています。コピーの前に、dest バッファーには、すべてのヌルを含め、何でも含めることができました。

strncpy は、コピー先のバッファの大きさを実際に伝えることでこれを解決します。これにより、収まりきらない量をコピーするケースを回避できます。

于 2009-10-21T16:08:26.733 に答える
0

以下を簡単に読むことをお勧めします。

http://en.wikipedia.org/wiki/Strncpy#strncpy

違いを示しています。基本的に、strncpy を使用すると、コピーするバイト数を指定できます。つまり、結果の文字列が必ずしも null で終了するとは限りません。

strcpy を使用してある文字列を別の文字列にコピーする場合、結果のメモリ領域が十分に大きいかどうかを確認することはありません。src 文字列のヌル文字までチェックします。

もちろん、この例の dst はわずか 5 バイトです。それでどうなるの?dest の最後まで書き込みを続け、メモリ内でそれを過ぎます。この場合、スタック上のメモリの次の部分は src 文字列です。したがって、コードが意図的にコピーしているわけではありませんが、メモリ内のバイトのレイアウトと dst の終わりを過ぎた書き込みが相まって、これが発生しました。

それが役立つことを願っています!

于 2009-10-21T15:58:44.420 に答える