3

いつものように、私はここでかなりの数の投稿を読んでいます。一般的なバス エラーに関する特定の有用な投稿を見つけました。ここを参照してください。私の問題は、特定のコードでエラーが発生する理由を理解できないことです。

私のコードは、C を独学するための試みです。これは、Java を学んだときに作成したゲームを修正したものです。私のゲームの目標は、単語の巨大な 5049 x 1 テキスト ファイルを取得することです。無作為に単語を選び、ごちゃまぜにして、推測してみてください。私はそのすべてを行う方法を知っています。とにかく、テキスト ファイルの各行には次のような単語が含まれています。

   5049
   must
   lean 
   better 
   program 
   now
   ...

そこで、C で文字列配列を作成し、この文字列配列を読み取って C に入れようとしました。他には何もしませんでした。ファイルを C に取り込めば、あとは簡単です。さらに奇妙なのは、準拠しているということです。コマンドで実行すると問題が発生し./blahます。

私が得るエラーは簡単です。それは言います:

zsh: bus error ./blah

私のコードは以下です。メモリやバッファのオーバーフローに関係しているのではないかと思いますが、それは完全に非科学的で直感的なものです. 私の質問は簡単です。なぜこの C コードでこのバス エラー メッセージが表示されるのですか?

#include<stdio.h>
#include<stdlib.h>

//Preprocessed Functions 
void jumblegame();
void readFile(char* [], int);


int main(int argc, char* argv[])
{
    jumblegame();

}

void jumblegame()
{
    //Load File 
        int x = 5049; //Rows
        int y = 256; //Colums
        char* words[x]; 
        readFile(words,x);

    //Define score variables 
        int totalScore = 0;
        int currentScore = 0; 

   //Repeatedly pick a random work, randomly jumble it, and let the user guess what it is

}

void readFile(char* array[5049], int x) 
{
    char line[256]; //This is to to grab each string in the file and put it in a line. 
    FILE *file;
    file = fopen("words.txt","r");

    //Check to make sure file can open 
    if(file == NULL)
    {
        printf("Error: File does not open.");
        exit(1);
    }
    //Otherwise, read file into array  
    else
    {
        while(!feof(file))//The file will loop until end of file
        {
           if((fgets(line,256,file))!= NULL)//If the line isn't empty
           {
               array[x] = fgets(line,256,file);//store string in line x of array 
               x++; //Increment to the next line 
           }    
        }
    }

}
4

6 に答える 6

5

この行にはいくつかの問題があります。

array[x] = fgets(line,256,file);//store string in line x of array 
  • 直前のifステートメントの条件で行を既に読んでいます。操作したい現在の行は既にバッファーにあり、次のfgets行を取得するために使用します。

  • 毎回同じ配列スロットに割り当てようとしています。代わりに、ループを介して毎回インクリメントする配列インデックス用の別の変数を保持する必要があります。

  • 最後に、を使用して文字列をコピーしようとしています=。これは参照をコピーするだけで、文字列の新しいコピーは作成しません。したがって、配列の各要素は同じ buffer: を指しline、関数が終了するとスコープ外になり、無効になります。文字列を入力するarrayには、配列用にそれぞれのコピーを作成する必要があります。 を使用して新しい文字列ごとにスペースを割り当てmalloc、 を使用strncpyしてそれぞれを新しい文字列にコピーlineします。または、 を使用できる場合はstrdup、スペースの割り当てを処理します。

しかし、これがバス エラーの原因であると思われます。配列サイズを として渡しx、ループで に代入していますarray[x]。これの問題は、それarray[x]が配列に属していないことです。配列には to の使用可能なインデックスしかありませ0(x - 1)

于 2012-07-30T18:35:49.427 に答える
2

x に値 5049 を渡しています。ラインが初めて

array[x] = ... 

実行すると、存在しない配列の場所にアクセスしています。

C を学んでいるようですね。早期に習得する必要があるスキルは、基本的なデバッガーの使用です。この場合、プログラムをコンパイルすると

gcc -g myprogram.c -o myprogram

そしてそれを実行します

gdb ./myprogram

(Linuxを想定しています)、バスエラーが発生した行を示すスタックダンプが得られます。これは、自分でエラーを把握するのに十分なはずであり、長期的には他の人に尋ねるよりもはるかに優れています.

デバッガーが役立つ方法は他にもたくさんありますが、これはリストの上位にあります。実行中のプログラムへのウィンドウが表示されます。

于 2012-07-30T18:37:15.400 に答える
0

readFile 関数内で定義されているライン バッファーに行を格納し、それへのポインターを arary に格納しています。これには 2 つの問題があります。新しい文字列が読み込まれるたびに値を上書きし、バッファがスタックにあることと、関数が戻ると無効になることです。

于 2012-07-30T18:38:31.047 に答える
0

少なくともいくつかの問題があります。

  • array[x] = fgets(line,256,file)

    これにより、のアドレスがline各配列要素に格納されます。linein が返されると無効にreadFile()なるため、役に立たないポインターの配列ができます。寿命が長くなったとしても、lineすべての配列要素に同じポインターを持たせることは役に立ちません (それぞれが最後にバッファーに書き込まれたものを指すだけです)。

  • while(!feof(file))

    これは、ファイルを読み取るためのアンチパターンです。http://c-faq.com/stdio/feof.htmlおよび「feof() の不適切な使用」を参照してください。このアンチパターンは、ファイルの読み取り時にプログラムが予想以上にループする原因となる可能性があります。

  • 5049 個のポインターを保持するように配列を割り当てますが、ファイル内の量を読み取るだけです。予想される数を読み取ったかどうか、または読み取りが多すぎるのを防ぐためのチェックはありません。ファイルを読み取るときに配列を動的に割り当てることを検討するか、適切な量のデータ (少なすぎず、多すぎない) を読み取り、正しくない場合にエラーを処理するメカニズムを用意する必要があります。

于 2012-07-30T18:48:54.920 に答える
0
char* array[5049], int x
array[x] = fgets(line,256,file)

長さ = 1 のメモリの場所である array[x] に代入し、ポインタ (4 バイト) を代入します。

一方、256 バイトの 2 倍を読み取ると、最初の 256 バイトが失われます。

しかし、重大な誤りは、最終条件 !feof() を置いたことです。これは、文字列配列の制限によってオーバーフローが発生することをチェックします。

于 2012-07-30T18:43:32.197 に答える
-1

に問題があると思われ(fgets(line,256,file))!=NULL)ます。ファイルを読み取るためのより良い方法はfread()( http://www.cplusplus.com/reference/clibrary/cstdio/fread/を参照) です。FILE*(C のファイル ストリーム)、バッファーのサイズ、およびバッファーを指定します。このルーチンは、読み取ったバイト数を返します。戻り値がゼロの場合、EOF に達しています。

char buff [256]; 
fread (file, sizeof(char), 256, buff); 
于 2012-07-30T18:35:01.460 に答える