9

私はstrncpyをいじっているだけです。

私のプログラムは次のようになります

typedef struct
{
    char from_str[10];
}test;

main ()
{

    test     s1;
    memset(&s1,0,sizeof(test));
    char       src[10]="himansh";
    char       dest[10];

    memset(dest,0,10);
    src[3]='\0';

    printf("src is %s and strlen is %d \n",
            src,strlen(src));

    fflush(stdout);

    strncpy(s1.from_str,src,100);

    printf("s1.from_str is %s , src is %s \n",
            s1.from_str,src);
    return 1;

}

ここで strncpy を実行する前に、「src」文字列に「\0」文字を追加しました。「src」文字列の長さは 3 になり、宛先配列のサイズは 10 になります。しかし、strncpy では、コピーするバイト数を 100 としています。 .

これは、ソース文字列が NULL で終了していることを意味します。これで、任意の文字列関数と同様に、strncpy は、提供するバイト数が 3 バイト (この場合は 100) を超える場合でも、3 バイトのみをコピーしようとする必要があります。それはそうしますが、セグメンテーション違反も発生します。

私の結果を以下に示します

src is him and strlen is 3
s1.from_str is him , src is him
Segmentation fault (core dumped)

なぜこのセグメンテーション違反がここで起こっているのですか。

ここで私を助けてくれる人はいますか?

4

4 に答える 4

18

マニュアル ページや Web サイトなどを紹介することもできますが、最終的に重要なのは C 標準そのものです。標準ランタイム ライブラリの一部として、使用法と動作は C99-§7.23.2.4 で次のように定義されています。

#include <string.h>
char *strncpy(char * restrict s1,
      const char * restrict s2,
      size_t n);

説明 このstrncpy関数は、s2 が指す配列から s1 が指す配列に最大 n 文字 (ヌル文字に続く文字はコピーされません) をコピーします。重複するオブジェクト間でコピーが行われる場合、動作は未定義です。s2 が指す配列が n 文字より短い文字列である場合、合計 n 文字が書き込まれるまで、s1 が指す配列内のコピーにヌル文字が追加されます。

戻りstrncpy値 関数は s1 の値を返し ます。

ここには重要な暗黙の情報があります。最も重要なのは、ソース文字列の長さ (ヌル文字ターミネーターを含まない) が指定された宛先バッファー長以上である場合、宛先文字列をヌル文字で終了させないことですstrncpy())

さらに、標準で明確に指定されていますが (上記を参照)、ソース文字strncpy() nの長さが宛先バッファ サイズ。これにより、次の避けられない結論が導き出されます。

API は常に、デスティネーション バッファが参照するアドレスに文字をstrncpy()書き込みます。n

あなたの場合、target-buffer の幅はわずか 10 文字であるため、書き込み可能なメモリの定義済みの終わりを超えて 90 文字を追加で書き込み、未定義の動作の土地に足を踏み入れています。

この時点で、「それで何の役に立つの?」と自問する必要があります。間違いなく基本的なユースケースがあります。nこれにより、過去の文字をオーバーランしないという予測可能性を備えたターゲット バッファーに最大文字をコピーできますn。限目。ただし、最終的には null で終わる文字列が必要なので適切な使用法は次のとおりです。

char dst[ N ]; 
strncpy(dst, src, N-1);
dst[N-1] = 0;

ここで、 は文字N単位のバッファのハード長で、dstより大きいか等しい1です。dst動的に割り当てられたメモリ ポインターである可能性があることに注意してください。

char *dst = malloc( N * sizeof(char) ); 
strncpy(dst, src, N-1);
dst[N-1] = 0;

上記の場合、常にnull で終わる文字列が になりdstます。ソース文字列の長さが指定されたターゲット バッファの長さよりも小さい場合、strncpy()source-chars-copied + tail-filled-null-characters の合計が と等しくなるまで、残りのバッファをヌル文字で埋めますn。最終ステートメントは次のとおりです。冗長。ソース文字列の長さがターゲット バッファ長以上strncpy()の場合、コピーを一度停止します。N-1chars に達し、最後のステートメントはバッファの最後にヌル文字を設定します。これにより、元のソースの「カットダウン」プレフィックス文字列が生成されますが、最も重要なことは、ターミネータをスキャンする後の文字列 API 呼び出しでターゲット バッファの境界を超えないようにすることです。

上記の手法の有用性については、常に議論の余地があります。私は C++ の男なのでstd::string、幸せな自分をこのすべての狂気から救います。しかし、現実srcは次のとおりです。時々あなたはしません。有用性は非常に状況に依存します。UI で文字列データを表示する場合、これは (おそらく) 問題になりません。重要なデータに使用する文字列をコピーする場合、partial-prefix-substring は受け入れられません。警察が「Joseph Johnson Jr.」に逮捕状を発行するとき、彼の父親 (「Joseph Johnson」) が刑務所に引きずり込まれたときに、逮捕状発行ソフトウェアの名前バッファーが 15 文字しか保持されていないため、説明する必要があります。 .dst

そうは言っても、セグメンテーションの誤りは次のステートメントに帰着します。

strncpy(s1.from_str,src, 100); // length parameter is wrong.

上記の太字のステートメントを思い出しください。strncpy()n. これは、上記のコードが常に100 文字をターゲット バッファーに書き込むことを意味します。この場合、幅は 10 文字しかないため、未定義の動作とker-boom の可能性があります。

ターゲット バッファーが固定長の文字配列である場合は、次の手順を実行してこれを修正します。

strncpy(s1.from_str,src, sizeof(s1.from_str)/sizeof(s1.from_str[0])-1);
s1.from_str[ sizeof(s1.from_str)/sizeof(s1.from_str[0])-1 ] = 0;

長さ `N 文字の動的文字列に対してこれを行う方法については、以前の使用法を参照してください。

于 2012-12-28T08:59:41.707 に答える
6

http://www.cplusplus.com/reference/cstring/strncpy/から

char * strncpy ( char * destination, const char * source, size_t num );

文字列から文字をコピー ソースの最初の num 文字をコピー先にコピーします。num 文字がコピーされる前にソース C 文字列 (null 文字によって通知される) の末尾が見つかった場合、合計 num 文字が書き込まれるまで、destination にゼロが埋め込まれます。

そのため、ソース文字列の長さが宛先バッファ サイズのサイズよりも小さい場合でも、strncpy の受け渡し動作のために、残りの文字を宛先バッファ サイズを超えてオーバーレイしようとするため、セグメンテーション エラーが発生します。

100文字を超えてコピーする代わりに、サイズは宛先バッファーの最大許容サイズと等しくなければならないため、次のように記述できます

strncpy(s1.from_str,src,sizeof(s1.from_str)/sizeof(s1.from_str[0]) - 1); Actual size -1 to accomodate the null terminator 

_countofまたはマクロを書く方が良い

#define _countof(s) (sizeof(s)/sizeof(s[0]))
................
strncpy(s1.from_str,src,_countof(s1.from_str) - 1);
于 2012-12-28T06:16:48.147 に答える
1

参照: http://www.manpagez.com/man/3/strncpy/

stpncpy() および strncpy() 関数は、最大 n 文字を s2 から s1 にコピーします。s2 の長さが n 文字未満の場合、s1 の残りは `\0' 文字で埋められます。それ以外の場合、s1 は終了しません。

残りは埋まりました……。

そう:

strncpy( s1.from_str, src, 10 );
于 2012-12-28T06:15:28.283 に答える
0

strncpy(s1.from_str,src,100);

関数で使用している理由は100、from_str と src の両方に 10 個の連続したバイトが割り当てられているのに、100 バイトをコピーしているため、seg. 障害。

このように使って、

strncpy(s1.from_str,src,10);

于 2012-12-28T06:20:08.197 に答える