2

これが私のコードです:

std::string readString()
{
     int strLen = Read<int>();
     char* rawString = new char[strLen];
     Read(rawString, strLen);
     rawString[strLen] = '\0';
     std::string retVal(rawString);
     delete [] rawString;
     return retVal;
 }

最初の行は文字列の長さを読み取ります。
2 行目は文字列の長さで新しい char 配列 (c-string) を作成します
。3 行目は文字列を読み取ります (ファイルから読み取ります)
。4 行目は最後に NULL を追加します。
5 行目は、c-string から std::string を作成します。
6 行目は c-string を削除します (HEAP CORRUPTION HAPPENS HERE)
7 行目は文字列を返しますが、エラーのためにこの時点には到達しません。

6 行目にヒープ破損エラーが表示されます。CRT は、アプリケーションがヒープ バッファーの終了後にメモリに書き込みを行ったことを検出しました。

私の質問は明らかかもしれませんが、なぜヒープが破損するのですか? std::string を作成すると、文字列がコピーされ、c-string を安全に削除できるはずです。

現在、std::string を削除した後、c-string が c-string にアクセスしようとしているのではないかと疑っています。

何か案は?

4

6 に答える 6

8

文字列用に予約されたバイトを超えてアクセスしています。文字を予約しましたが、文字strLenにaを付けます。0からC配列として数えると、文字は位置にあるため、文字列用に予約されたスペースの外に値を配置します。コードが機能するように、2行目で予約する必要があります。\0strLenstrLenstrLen + 1strLen + 1main

于 2010-11-18T21:09:47.483 に答える
4

変化する:

char* rawString = new char[strLen];

に:

char* rawString = new char[strLen + 1];
于 2010-11-18T21:09:57.247 に答える
2

int strLen = Read<int>() おそらく\0、nullで終了していない文字列の長さのみを返し、その文字列にバイトを書き込もうとすると、バッファオーバーフローの問題が発生します。

あなたは何であるかをチェックする必要strLenがあります、そしておそらくあなたは次のように割り当てる必要があります:

char *rawString = new char[strlen+1];

または、次のstd::string(const char *, size_t n)ようなオーバーロードされたコンストラクターを使用します。

std::string retVal(rawString, strlen);
于 2010-11-18T21:09:28.713 に答える
1

これまでに多くのアドバイスがありましたが、例外安全性の問題に対処するアドバイスはありません。潜在的なメモリリークをどのように取り除くのですか?

での割り当てを回避するnew(したがって、メモリリークに直面する)のを回避する方法は2つあります。1つ目は非常に単純で、可変長配列のVLAと呼ばれるコンパイラ拡張を利用します。

std::string readString()
{
  int strLen = Read<int>();
  char rawString[strLen+1]; // VLA: the length is determined at runtime
                            // but the array is nonetheless on the stack
  Read(rawString, strLen);
  rawString[strLen] = '\0';

  std::string retVal(rawString);
  return retVal;
}

もう1つは標準に準拠しています:stringアクセスできる内部バッファがあります(GManのおかげでdata、正しいアクセス方法ではありません)

std::string readString()
{
  int strLen = Read<int>();

  std::string retVal(strLen, '\0'); // no need to allocate extra space

  Read(&retVal[0], strLen);      // &retVal[0] gives access to the buffer

  return retVal;
}

私は最後のバージョンがはるかに優れていると信じています。関係するコピーはもうありません:)

于 2010-11-19T07:42:07.480 に答える
1

配列はC++では0インデックスであるため、サイズの配列を作成し、strLen位置に0を配置するstrLenと、割り当てた配列の終わりの後にそのゼロが1つ書き込まれます。

于 2010-11-18T21:10:36.130 に答える
0
 rawString[strLen] = '\0';

割り当てたスペースの最後からNULを書き込みます。

strLenが10の場合、10文字にスペースを割り当て、10文字を読み取り、このNULを位置11に書き込みます。おっと

于 2010-11-18T21:11:16.840 に答える