0

テキスト ファイルから一連の int を 2D 配列に読み込むプログラムを作成しています。
このファイルには、間にスペースを入れない 81 個の数字の 40 行が含まれています。

array[0][0]問題は、ループが終了した後に配列を計算するとarray[0][1]、予想される出力の前後に2つの乱数が出力されることです。改行/改行文字に関係していると思います。ループの最初の反復は完全に実行されます。コードは次のとおりです。

#include <cstring>
#include <cstdlib>
#include <iostream>
#include <fstream>

using namespace std;

int main()
{
  int array[9][9];

  //Open file:

  fstream ifile;

  ifile.open("numbers.txt", ios::in);
  if (ifile.fail())
    {
      cout << "Could not open numbers.txt" << endl;
      return -1;
    }

   while (!ifile.eof())
    {
      for(int i=0; i<9; i++)
      {   
    for(int j=0; j<9; j++)
    {
       int n = ifile.get();
              if(isdigit(n)) 
            {
                  array[i][j] = n - '0';
        }

          cout<<"array ["<<i<<"]["<<j<<"] is "<<array[i][j]<<endl;
      } 
      } cout<<"This is a test"<<endl;
    }

  return 0;
}
4

3 に答える 3

2

外側のループの目的がまったくわかりません。まず、file と等しくなることはありませんeof()、または...eof()とにかく、 とは何ですか? 第 2 に、実際に を書いたことがあればwhile ( !file.eof() )、一部の要素が上書きされるという事実を説明できる可能性があります。最後の桁の後にいくつかの末尾の文字 (少なくとも新しい行) がある可能性が高いため、ループに再び入ります。

また、読み取った文字が数字ではない場合でも、インデックスをインクリメントしています。データが 9 行 9 桁の場合grid、内部の 2 回の反復が終了すると、初期化されていない 9 つのセルと、ファイルから読み取られていない 9 つの文字が発生します。したがって、これらの文字を読み取って、外側のループに再び入ります。そのうちのいくつかは数字になるため、gridすでに書いたセルを上書きすることになります。これはおそらく、観察している効果です。また、ファイルの最後に到達すると、 通常は-1file.get()が返されます。と のテストが機能しなかったEOFのは間違いなくそのためです。'\n''\r'

そして、これらは正しくフォーマットされたファイルの問題です。正しくフォーマットされたファイルの場合file >> n、 , withchar n;を使用するだけでほとんど機能します。operator>>空白をスキップします。file.eof()ただし、入力が失敗するまで信頼できないため、もう一度最も外側のループに入ります。あなたは「これを使わなければならない」と言いますが、それを変更しない限り、あなたのコードは機能しません。

個人的には、多くのエラー チェックを備えた堅牢なソリューションを好みます。を使用std::getline()し、各行に正確に 9 桁が含まれていることを確認します。何かのようなもの:

std::string line;
int i = 0;
while ( i < 9 && std::getline( file, line ) ) {
    if ( line.size() != 9 ) {
        throw FormatError( "wrong line length" );
    }
    for ( int j = 0; j != 9; ++ j ) {
        if ( ! isdigit( static_cast<unsigned char>( line[j] ) ) ) {
            throw FormatError( "illegal character" );
        }
        grid[i][j] = line[i] - '0';
    }
}
if ( i != 9 || std::getline( file, line ) ) {
    throw FormatError( "wrong line count" );
}

file.get()を使用して一度に 1 文字ずつ読み取るのはそれほど難しくありませんが、読み取るEOFたびに確認する必要があります。

for ( int i = 0; i != 9; ++ i ) {
    for ( int j = 0; j != 9; ++ j ) {
        int ch = file.get();
        if ( ch == EOF ) {
            throw FormatError( j == 0 
                                ? "line too short" 
                                : "too few lines" );
        }
        if ( !isdigit( ch ) ) {
            throw FormatError( "illegal character" );
        }
        grid[i][j] = ch - '0';
    }
    int ch = file.get();
    if ( ch != '\n' ) {
        throw FormatError( ch == EOF ? "too few lines" : "line too long" );
    }
}
if ( file.get() != EOF ) {
    throw FormatError( "too many lines" );
}
于 2012-04-05T17:02:35.923 に答える
1

jに書き込むかどうかに関係なくインクリメントするため、乱数が表示されますgrid[i][j]

内側のループを次のように置き換えてみてください。

for(int j=0; j<9; )
{
  int n = file.get();
  if(!file) break;
  if(isdigit(n))
  {
    array[i][j] = n - '0';
    cout<<"array ["<<i<<"]["<<j<<"] is "<<array[i][j]<<endl;
    j++;
  }
  cout<<"grid ["<<i<<"]["<<j<<"] is "<<grid[i][j]<<endl;
} 
于 2012-04-05T16:42:23.937 に答える
1

eofファイルの最後に達したときに設定されず、読み取りが失敗した後に設定されます。そして、その最後の読み取りからのデータは、失敗したため、もちろん無効です。現在のコードは無効なデータを使用しています...


それを超えて、file != eof()あらゆる種類の間違いがあります。::eof()関数がなくiostream::eof()、オブジェクトが必要なため、コンパイルすることさえできません。 file != EOFコンパイルされる可能性がありますが、その後filebool に変換され、int に昇格されます (0または)。 ( )1と等しくなることはありません。あなたが意味したのは でしたが、上記の理由からそれも間違っています。EOF-1!file.eof()

于 2012-04-05T16:45:14.790 に答える