1
    char test[]={"abcde"};
    char* test1={"xyz"};
    memcpy(test+5,test1,3);
    printf("%s",test);

memcpyがどのように機能するかを正確に把握しようとしています。これは、これまでに作成した例です。これにより、次のように出力されますabcdexyz&vjunkcharacters

そして次のメッセージ。

*** stack smashing detected ***: ./testcode terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0xb7656dd5]
/lib/i386-linux-gnu/libc.so.6(+0xffd8a)[0xb7656d8a]
./testcode[0x8048797]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb75704d3]
./testcode[0x80483a1]

この状況の背後にある理由は何ですか?

4

5 に答える 5

4

根本的な原因:

char test[]={"abcde"};

5文字のみ を格納するのに十分なメモリ スペースを割り当てます。

memcpy(test+5,test1,3);  

test1が指すデータを、割り当てられたメモリ空間を超えてコピーします。
技術的には、この方法で割り当てられたメモリの境界を超えて書き込むことはUndefined Behaviorです。つまり、何でも起こり得るということです。

実際にはどうなりますか?

ここで実際に起こることはmemcpy、割り当てられたメモリを超えて文字をコピーNULLし、文字配列の終わりを示すターミネータを上書きすることtestです。
さらに、ランダムに遭遇するまでprintfの開始アドレスからコンテンツを読み取り、ジャンク文字を出力します。 testNULL

解決策:
を実行する前に、宛先バッファに十分なメモリが割り当てられていることを確認する必要がありmemcpyます。文字をコピーするつもりなので3、宛先バッファtestは少なくとも次のように する必要があります。

5 + 3 + 1 byte for NULL terminator = 9 bytes

以下を簡単に使用できます。

char test[9]="abcde";
于 2012-09-26T06:49:26.500 に答える
2

あなたのmemcpy呼び出しスタックを破壊するため、そのメッセージが表示されます。test許可されていない配列の末尾を超えてデータをコピーしています。

于 2012-09-26T06:44:40.403 に答える
2

追加のバッファなしでそれを行う

実際、最も簡単なアプローチは、コピーを避けることです。

#include <string.h>
#include <stdio.h>

int main() {
  char a[] = "abcde";
  char b[] = "xyz";
  printf("%s%s\n", a, b);
  return 0;
}

memcpyでそれを行う

memcpyは、nバイトを からsrcにコピーしますdest。文字列のヌル終了バイトを自分で正しくコピーすることを追跡する必要があります。

#include <string.h>
#include <stdio.h>

int main() {
  char a[] = "abcde";
  char b[] = "xyz";

  /* note that both strings add a '\0' termination */
  char c[sizeof(a) + sizeof(b) - 1];

  /* copy the content of a to c */
  memcpy(c, a, sizeof(a));

  /* copy the content of b to where a ends (concatenate the strings) */
  memcpy(c + sizeof(a) - 1, b, sizeof(b));

  /* note that the '\0' termination of the string is necessary to let
   * functions like printf know where the string is over 
   */
  printf(c);

  return 0;
}

strcpy と strcat でそれを行う

memcpy を使用する場合、文字列の null 終端を正しく処理するには多くの落とし穴があることに注意してください。文字列のこの手順を簡素化するには、次の手順を実行する必要があります。

これらが実際に文字列であり、ランダムなバイトではない場合は、標準ライブラリの文字列関数に固執する必要があります。これがその方法です。

#include <string.h>
#include <stdio.h>

int main() {
  char a[] = "abcde";
  char b[] = "xyz";

  /* note that both strings add a '\0' termination */
  char c[sizeof(a) + sizeof(b) - 1];

  /* copy the content of a to c */
  strcpy(c, a);

  /* copy the content of b to where a ends (concatenate the strings) */
  strcat(c, b);

  /* note that the '\0' termination of the string is necessary to let
   * functions like printf know where the string is over 
   */
  printf(c);

  return 0;
}

弦の大きさを知る上で

バッファのサイズを知ることに関しては、通常は単純にできないことに注意してくださいsizeof(a_string)。文字配列を関数に渡すと、ポインターに減衰し、この操作は配列の予想されるサイズではなく、ポインターのサイズを返します。

strlen(a_string)文字列の場合は、null 終端の発生をスキャンし、文字列の長さ (終端を含まない) を返すを発行する必要があります。

ランダム データを含む文字バッファー (または書き込みが必要な空のバッファー) については、このアプローチも機能しません。追加のパラメーターとしてバッファーのサイズを常に渡す必要があります。

于 2012-09-26T07:03:02.123 に答える
1

変数test1は、メモリ内に4文字、3に加えて終了文字列ターミネータがあります。これを試して:

char test[9]={"abcde"};
char* test1={"xyz"};
memcpy(test+5,test1,4);
于 2012-09-26T06:52:51.580 に答える
1

この行memcpy(test+5,test1,3);は、平易な言葉で次のことを行います。

「配列「test」の最後の要素から開始し、配列「test1」から3文字をそこにコピーします」、これは基本的に配列「test」の長さを超えて2文字を書き込みます。

したがって、「memcpy」をいじりたいだけの場合は、3 番目の配列を定義します。

char test[]="abcde";
char test1[]="xyz";
char output[sizeof(test) + sizeof(test1)];
memset(output, 0, sizeof(output));
memcpy(&output[0],test,5);
memcpy(&output[5],test1,3);
printf("%s",output);
于 2012-09-26T06:51:06.593 に答える