2010-12-02 22 views
1

3つのフィールドがカンマで区切られたテキストファイルがあります。 私のテキストファイルの内容の例:12345、真のプログラミングnewbie、BS ME ファイルをプログラムに読み込むために、私は以下のコードを使用しました....私の問題は、コードが動作することがあり、 (エラーメッセージは表示されず、プログラムは終了し、続行されません)。私はまた、テキストファイルが空白(何も書かれていない)それが自動的に閉じて、継続しないことを観察した。あなたの助けが高く評価されるでしょう。ありがとう!fgets()とstrtok()を使ってカンマ区切り文字でファイルを読む

int read(){ 
    FILE *stream = NULL; 
    int ctr; 
    char linebuffer[45]; 
    char delims[]=", "; 
    char *number[3]; 
    char *token = NULL; 
    stream = fopen("student.txt", "rt"); 
    if (stream == NULL) stream = fopen("student.txt", "wt"); 
    else { 
      printf("\nReading the student list directory. Wait a moment please..."); 
      while(!feof(stream)){    
       ctr=0; 
       fgets(linebuffer, 46, stream); 
       token = strtok(linebuffer, delims); 
       while(token != NULL){ 
        number[ctr] = linebuffer; 
        token = strtok(NULL, delims); 
        ctr++; 
       } 
      recordCtr++;      
      }      
    recordCtr--; 
    } 
    fclose(stream); 
}  
+0

なぜあなたの質問に非常に多くの点を使用していますか?それは恐ろしいね。 – unwind

答えて

2

見つけたらtokenをコピーしないでください。 linebufferをコピーすることはできません。そのデータは、次の行がロードされるときに上書きされるためです。

このライン:

number[ctr] = linebuffer; 

は、最近検出されたトークンを保存するためにtokenを参照する必要がありますが、それはしていません。それはおそらくような何かお読みください:

strcpy(number[ctr], token); 

をしかし、あなたはスペースがありますことを確認する宣言を変更する必要があると思います:明らかに

char number[3][32]; 

が、これがあれば、バッファオーバーランのリスクを紹介します非常に長いトークンがあり、適合しません。それを最良に処理する方法は、運動として残されています。 :)

2つの数字と1つの文字列(名前)を格納するために使用されると、なぜ一時的なベクトルが「番号」と呼ばれるのはなぜですか?

+0

@unwind申し訳ありません。わかりません。あなたは私にもっと説明をお願いできますか?ありがとう – newbie

+0

彼は "strtok()"によって返された "トークン"を取得した後、それを投げ捨てることを意味します。代わりに、 "linebuffer"をフィールドに割り当てます。 – AlastairG

+0

@unwind素敵な答えですが、私はあなたよりも多くのバグと潜在的なバグを見つけたと思います;)私は競争が激しいのですか? – AlastairG

1

あなたのfgets()呼び出しは、サイズとして45を指定する必要があります。あるいは、fgetsがNULLターミネータを書き込むときにバッファをオーバーフローさせる必要があります。これは、 "delims"文字列を空の文字列に設定します。

また、関数宣言によってintが返されたとしても、値は返されません。

"struct student"の定義が何であるか分かりませんが、strcpy()を使用しているときにバッファがあふれている可能性があります。また、 "recordCtr"を減らします。どうして?あなたが書き込み用にそれを開くことができない場合、なぜあなたは書き込みのためにファイルを開きますか?どうして?それでも失敗した場合は、NULLポインタでfcloseを呼び出します。私はそれが多くを助けることを疑う。

「番号」を初期化していないことに気付きました。最初の行に3つの数字がない場合は、初期化されていないポインタからstrcpy()を取得します。おそらくNULL値を持つので、プログラムはsegfaultになります。

また、サイズが3の配列がありますが、読み込んだ行に3つ以上のカンマ区切りフィールドがある場合は、配列がオーバーフローします。

おそらく他にも多くのエラーがあります。

多くのプログラマーは、戻り値のチェック、変数の初期化などのような優れたコーディングの慣行をするのに気を取ることはできません。彼らはしばしばこのようなコードで終わる。あなたが本当に良いプログラマになりたいなら、これらすべてのことをやってみたり、少なくともあなたが必要とするかどうかについて常に考えてみてください。

このコードには非常に多くの潜在的なバグがあります。行の長さが45文字を超えるとどうなりますか?改行は取り除かないでください。あなたは文字列を数値に変換しません(number [1]は文字列データのように見えますが、なぜ "numbers"という配列に格納するのでしょうか?)、または実際にデータを返すか、取得する。

+0

私は5文字(IDの場合)、30文字(学生名の場合)、5文字(コースの場合)しか許されないので、私は46の長さにしました。その後、余分な5を作成します。私のロジックは間違っていますか?ありがとう – newbie

+0

私の関数宣言はintであるためvoidに変更しました。コンパイラエラーがあります – newbie

+0

おそらく 'read()'がシステム関数であるためです。別の名前に変更してみてください。職場では、すべてのパブリック関数は、それらが含まれているモジュール/コンポーネントの名前で始まらなければならないというコーディング標準を持っています。例えば。あなたはそれをStudentDB_Read()と呼ぶことができます。 – AlastairG

1

買い手に注意を促してください。

strtokには、いくつかの悩みがあるかもしれません。

「1,2,3」は3つのトークンを生成します。

"one ,, three"は2つのトークンを生成します。

+0

それはどういう意味ですか? – newbie

+0

それはそれが言うことを意味します。あなたは "トークン"が何であるか理解していますか?そうでなければ、 'strtok'を使うべきではありません。あなたは「strtok」の「tok」が短いと思いましたか? –