1

誰かが私のジレンマを解決するのを手伝ってくれますか? プログラムをコンパイルしても、エラーや警告は表示されません。ただし、実際に実行可能ファイルを実行すると、セグメンテーション エラーが発生します。私の理解が正しければ、これは要するにポインターが間違って使用されているために発生します。feof(srcIn) 行で特定のエラーが発生しましたが、その理由がわかりません。FILE* srcIn には、プログラムの先頭にある srcIn = fopen(argv[0], "r") 値以外の新しい値が割り当てられることはありません。私はもともとこのソリューションを C++ で実装していましたが、理由により C に変更する必要がありました。とにかく、C++ では、条件として srcIn.eof() を使用し、読み取りメソッドとして srcIn.get(something) を使用することを除いて、本質的にまったく同じことを行いました。問題なくコンパイルして実行できました。

int chara;
int line[maxLineLength+1];

void nextch(void){
    const int charPerTab = 8;
    if(charCounter == charLineCounter){
      if(feof(srcIn)){
          printf("\n");
          isEOF = TRUE;
          return;
      }

      printf("\n"); lineCounter++;
      if(chara != '\0'){ printf("%c", line[charLineCounter-1]); } // first character each line after the first line will be skipped otherwise
      charLineCounter = 0; charCounter = 0;
      while(chara != '\n'){
         chara = fgetc(srcIn);
         if(chara >= ' '){
            printf("%c", chara);
            line[charLineCounter] = chara; charLineCounter++;
         }
         else if(chara == '\t'){  // add blanks to next tab
            do{ printf(" "); line[charLineCounter] = ' '; charLineCounter++; }
            while(charLineCounter % charPerTab != 1);
         }
      }
      printf("\n"); line[charLineCounter] = chara; charLineCounter++; line[charLineCounter] = fgetc(srcIn); charLineCounter++;
                                                                      // have to get the next character otherwise it will be skipped
   }
   chara = line[charCounter]; charCounter++;
}

編集:セグフォルトが発生したときに、実際にはメインにさえ入っていないことを忘れていました。これにより、実行可能ファイル自体に何らかの問題があると思われます。gdb は、セグメント障害が次の行で発生していることを教えてくれます: if(feof(srcIn)) 何かアイデアはありますか?

4

4 に答える 4

2

2 文字または 4 文字のインデントでは、プログラムの実際の範囲を理解するには不十分ではないかと、私は頭から離れません。@mu が短すぎて @Null Set が指摘するのと同じくらい簡単かもしれません。argv[0]あなたが意図したときに を持っていることを意味しargv[1]、@Lou Franco が指摘するように、配列の末尾を超えて書いている可能性があります。しかし、このコードは確かに変なにおいがします。これがコードです。実行しLindentて、より大きなタブと1行に1つのステートメントを取得します。

int chara;
int line[maxLineLength + 1];

void nextch(void)
{
    const int charPerTab = 8;
    if (charCounter == charLineCounter) {
            if (feof(srcIn)) {
                    printf("\n");
                    isEOF = TRUE;
                    return;
            }

            printf("\n");
            lineCounter++;
            if (chara != '\0') {
                    printf("%c", line[charLineCounter - 1]);
            }               // first character each line after the first line will be skipped otherwise
            charLineCounter = 0;
            charCounter = 0;
            while (chara != '\n') {
                    chara = fgetc(srcIn);
                    if (chara >= ' ') {
                            printf("%c", chara);
                            line[charLineCounter] = chara;
                            charLineCounter++;
                    } else if (chara == '\t') {     // add blanks to next tab
                            do {
                                    printf(" ");
                                    line[charLineCounter] = ' ';
                                    charLineCounter++;
                            }
                            while (charLineCounter % charPerTab != 1);
                    }
            }
            printf("\n");
            line[charLineCounter] = chara;
            charLineCounter++;
            line[charLineCounter] = fgetc(srcIn);
            charLineCounter++;
            // have to get the next character otherwise it will be skipped
    }
    chara = line[charCounter];
    charCounter++;
}

ifステートメントの一番上にあるファイルの最後まで読んだかどうかを確認していますが、二度と確認することはありませんeof。一度もない。while()ループで入力から読み取るときは'\n'、終了条件として を使用し、文字が の上にある場合は出力を出力し、' 'を読み取った場合はタブ展開を行い、からの戻り'\t'を処理するのを忘れました。入力ファイルに. 入力ファイルが で直接終了していない場合、このプログラムはおそらくsegfault するまで配列に書き込みます。EOFfgetc(3)'\n'-1line'\n'-1line

入力ストリームから 1 文字を読み取って操作するほとんどのループは、次のように記述されます。

int c;
FILE *f = fopen("foo", "r");

if (!f) {
    /* error message if appropriate */
    return;
}

while ((c=fgetc(f)) != EOF) {
    if (' ' < c) {
        putchar(c);
        line[counter++] = c;
    } else if ('\t' == c) {
        /* complex tab code */
    } else if ('\n' == c) {
        putchar('\n');
        line[counter++] = c;
    }
}

の入力を確認しますEOF。可能であれば、1 つの場所からのみ入力を読み取ります。1 つのテーブルまたはif/ else if/ else if/ツリーを使用elseして、入力文字をどうするかを決定します。array[index++] = value;最初はイディオムを使うのは自然なことではないかもしれませんが、C では一般的です。

あなた自身のコード用に私が提案したループ形式を自由に盗用して、複雑なタブ拡張コードを挿入してください。あなたはそれを正しく理解しているように見えましたが、私はそれについて肯定的ではなく、ループの全体的なスタイルから気を散らしたくありませんでした. あなたの問題を解決するために私のコードを拡張することは、あなたの問題を機能させるよりも簡単であることがわかると思います。(できるとは思いますが、維持するのは楽しいとは思いません。)

于 2011-04-01T20:21:10.973 に答える
1

argv[0]あなたのプログラムの名前なので、fopen(argv[0], 'r')おそらく失敗しています。argv[1]代わりに開きたいと思います。そしてもちろん、fopen戻り値を使用する前に、が成功することを確認してください。

于 2011-04-01T19:52:42.187 に答える
1

この関数には含まれていない可能性がありますが、問題がここにある場合は、オンラインで範囲外になる可能性が最も高いと思われます。文字以上のものを書いたことはありmaxLineLengthますか? 行にインデックスを付ける前に、チェックを入れる必要があります。

編集: このエラーが何を意味するのかさえ混乱しているようです-私はそれを片付けようとします.

セグメンテーション違反が発生した場合、それが発生した行は、メモリの破損が最終的に検出されたコード行です。必ずしも実際の問題とは関係ありません。あなたがしなければならないことは、そもそも破損がどこで発生したかを突き止めることです。

非常に一般的な原因:

  1. ポインターで free または delete を複数回呼び出す
  2. ポインターで間違った削除を呼び出す (delete または delete[])
  3. 初期化されていないポインターの使用
  4. free または delete が呼び出された後にポインターを使用する
  5. 配列の範囲外に出ます(これはあなたがしたと思います)
  6. 間違った型へのポインタのキャスト
  7. ターゲットの型を正しく再解釈できない reinterpret_cast を実行する
  8. 不適切な呼び出し規則で関数を呼び出す
  9. 一時オブジェクトへのポインターを保持する

そして、他にも多くの方法があります。

これを理解するための鍵は、

  1. あなたのコードが間違っていると仮定します
  2. コード パスを調べて、この種の問題を探します (短い場合)。
  3. 問題を起こしたコード行にこれらの問題があることを教えてくれるツールを使用する
  4. セグメンテーション違反が発生するコード行が必ずしもバグではないことに気付きます。
于 2011-04-01T19:53:05.993 に答える
1

おそらくsrcIn = fopen(argv[1], "r")代わりになるはずです。main が取得する0th 文字列パラメーターは、通常、プログラムの名前であり、1st パラメーターは、プログラムに渡した最初のコマンド ライン パラメーターです。

于 2011-04-01T19:53:22.593 に答える