0

我正在开发一个程序,该程序将文本文件中的一系列整数读取到二维数组中。
该文件包含 40 行,每行 81 个数字,它们之间没有空格。

问题是,当我在循环完成后计算数组时,它会在预期输出之前array[0][0]和之前输出 2 个随机数。array[0][1]我认为这与换行符/回车符有关。循环的第一次迭代运行完美。这是代码:

#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(),无论如何?其次,如果你真的写过while ( !file.eof() ),这可以解释一些元素被覆盖的事实。在最后一个数字之后可能会有一些尾随字符(至少是一个新行),因此您将再次重新进入循环。

即使您读取的字符不是数字,您也会增加索引。如果数据是 9 行,每行 9 位数字,grid则在完成内部两次迭代后,您将得到 9 个尚未初始化的单元格,以及尚未从文件中读取的 9 个字符。因此,您将再次进入外循环,读取这些字符。其中一些是数字,所以你最终会覆盖grid你已经写过的单元格——这可能是你观察到的效果。此外,一旦您到达文件末尾, file.get()将开始返回- 通常为EOF-1。毫无疑问,这就是为什么您的测试无效'\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(),一次读取一个字符,但您仍然需要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可能会编译,但随后file会被转换为 bool 并提升为 int(0或者1),它永远不会等于EOF( -1)。您的意思是!file.eof(),但由于上述原因,这也是错误的。

于 2012-04-05T16:45:14.790 回答