9

私は課題のテールの実装に取り​​組んでいます。私はそれを正しく動作させていますが、ランダムな時間に無料でエラーが発生しているようです。

一貫性がある以外のパターンや何かにそれを追跡するために、私は見ることができません。

たとえば、プログラムを「tail -24 test.in」と呼ぶと、複数回実行すると同じ行で誤ったチェックサムエラーが発生します。ただし、ファイルが異なり、印刷する行数が異なる場合でも、エラーなしで戻ってきます。

問題を追跡する方法についてのアイデアは、何時間も無駄にデバッグしようとしてきました。

問題のあるコードは次のとおりです。

行はchar**として定義され、mallocは次のようになります。

lines = (char**) malloc(nlines * sizeof(char *));

void insert_line(char *s, int len){

  printf("\t\tLine Number: %d Putting a %d line into slot: %d\n",processed,len,slot);
  if(processed > numlines -1){//clean up
    free(*(lines+slot));
    *(lines + slot) = NULL;
  }
  *(lines + slot) = (char *) malloc(len * sizeof(char));
  if(*(lines + slot) == NULL) exit(EXIT_FAILURE);
  strcpy(*(lines+slot),s);
  slot = ++processed % numlines;
}
4

6 に答える 6

7

ルーチンが、割り当てられたライン バッファーを超えて書き込みを行っています。

引数として渡される行のサイズ (つまり "len") には、おそらく NUL ターミネータが含まれていません。行 (つまり "s") をコピーするために malloc を呼び出すときは、文字列ターミネータに追加のバイトを割り当てる必要があります。

 *(lines + slot) = (char *) malloc((len + 1) * sizeof(char));
于 2008-10-24T13:30:43.460 に答える
4

特定の入力パラメーターで一貫して問題を再現できる場合は、次のようにデバッグする必要があります。

  • 最初に、問題の原因となっている正確な空き領域までデバッグします。
  • 次に、解放しようとしているメモリがいつ malloc されたかを調べます。
  • 次に、メモリが malloc されている場所までデバッグします。
  • メモリ ビューアで、割り当てられたメモリ ブロックを見つけます。ブロックの開始と終了の両方に注意してください。ブロックの直前と直後にガードブロックと呼ばれる特殊な値が存在する可能性があります。
  • メモリが解放されるまで、コードをステップ実行します。ある時点で、コードは誤ってガード ブロックを上書きするはずです。それが問題の発言です。

問題は、プログラムのまったく別の部分にある可能性が非常に高いことに注意してください。エラーを報告しているのはこのフリーですが、ガード ブロックを上書きするコードはどこにでもある可能性があります。

于 2008-10-24T07:32:39.793 に答える
1

私の最初の質問は、len をどのように計算するのですか? strlen だけですか、それとも \0 ターミネータ用のスペースが含まれていますか? strcpy での割り当てをオーバーシュートしている可能性があると思います。不適切な動作は、単語の境界で発生する傾向があり、ランダムに表示されます。また、ソース文字列が null で終了していることを確認してください。読み取り側でミスをして終了しなかった場合。次に、strcpy がランダムに上書きしている可能性があります。

  *(lines + slot) = (char *) malloc(len * sizeof(char));
  if(*(lines + slot) == NULL) exit(EXIT_FAILURE);
  strcpy(*(lines+slot),s);

おそらく試してみてください:

  lines[slot] = (char *) malloc((len + 1) * sizeof(char));
  if(lines[slot] == NULL) exit(EXIT_FAILURE);
  if(strlen(s) <= len){
    strcpy(lines[slot],s);
  }
  else{
    /* do something else... */
  }

一般的な形式に関しては、全体をもう少し読みやすく、理解しやすく、エラーに強いものにするために、いくつかの文体の変更を加えることもお勧めします。

ポインター演算は有効で楽しいですが、次のような配列形式を使用すると、意図がもう少し明確になると思います。

free(lines[slot]);
lines[slot] = NULL;

それ以外の

free(*(lines+slot));
*(lines + slot) = NULL;

また、使用する static を減らすことをお勧めします。それらをデータ構造で調べて、アクセサーとミューテーターに渡すのは簡単です。アクションが発生している場所がより明確になり、次のようなことができなくなります。

static int numlines = 0;
void insert_line(char *s, int len){
    int numlines = 5;

デバッグするのが悲惨なスコーピングの問題を導入できます。

于 2008-10-24T12:58:45.007 に答える
0

nlines と numlines は同じ値ですか?

2 番目のパラメーターで長さを渡すときに、insert_line の呼び出し元が末尾の NUL の余地を許可しますか?

于 2008-10-24T07:11:10.417 に答える
0

関連しているかどうかはわかりませんが、次の 2 行は疑わしいと思われます。

  *(lines + slot) = (char *) malloc(len * sizeof(char));
  if((lines + slot) == NULL) exit(EXIT_FAILURE);

最初に malloc の戻り値を割り当ててからlines[slot]、チェック(lines+slot)します。後者が NULL の場合は、NULL ポインターを逆参照していました。

また、lines[slot] (your *(lines+slot)) が null でない場合、malloc() の結果をそれに割り当てるときにメモリ リークが発生します。

lineschar*lines[]` であり、スロットは許可された境界内にあると想定しています!

于 2008-10-24T07:18:08.980 に答える
0

私は、これらの 2 つの行に関する remo の疑いには同意しますが、remo が行った接線には同意しません。このバグを発見した功績を共有する必要があります。

*(lines + slot) = some value
if((lines + slot) == NULL) then die
should be
if(*(lines + slot) == NULL) then die
于 2008-10-24T07:23:48.627 に答える