2012-04-05 74 views
0

我正在研究从文本文件读取一系列整数到二维数组中的程序。
该文件包含40行81个数字,它们之间没有空格。file.get()在循环后返回随机数C++

问题是,当我在循环完成后关闭数组时,它会在预期输出之前在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; 
} 
+0

你的输入文件是怎样的? – 2012-04-05 16:29:25

+0

1)你不测试'file.get()'是否成功。 2)即使'n'不是一个数字,你也会增加'j',并且3)**请**提供一个简短而完整的程序,用来证明你所遇到的错误。请参阅http://sscce.org/。 – 2012-04-05 16:31:50

+0

@KornelKisielewicz这是一个包含40行81个数字的文件,它们之间没有空格 – adohertyd 2012-04-05 16:32:06

回答

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; 
} 
+0

为什么它值得我包含一个工作程序Rob – adohertyd 2012-04-05 17:03:04

+0

这是值得的。我编辑了我的答案。它现在提供了正确的解决方案。 – 2012-04-05 17:58:34

1

eof当到达文件的结尾没有设置,这是一个读取失败后进行设置。而上次读取的数据当然是无效的,因为它失败了。您当前的代码使用无效数据...


除此之外,file != eof()是各种错误。它甚至不应该编译,因为没有::eof()函数,并且iostream::eof()需要一个对象。 file != EOF可能会编译,但随后file将转换为bool并提升为int(01),但它永远不会等于EOF-1)。你的意思是!file.eof(),但这也是错误的,因为上面给出的原因。

+0

你的陈述当然是真的。但是*错误并不能解释他的抱怨。即“array [0] [0]'和'array [0] [1]'”中的2个随机数。 – 2012-04-05 16:46:57

+0

@Rob:当然了,他在检查'eof()'之前多次调用'file.get()'。 – 2012-04-05 16:47:57

+0

@Rob它的确如此,因为通过提高索引的速度比消耗数字更快,他最终将外部循环取两次,覆盖了一些早期的数字。 – 2012-04-05 17:04:17

2

我完全不理解外层循环的目的。首先,file 永远不会等于eof(),或...什么是eof(),有什么办法?其次,如果你实际上写了while (!file.eof()),这可能是 解释了一些元素被覆盖的事实。在最后的 数字后面会有 可能是一些尾随字符(至少一个新行),因此您将再次重新进入循环。

即使您阅读的字符不是 而不是数字,也会增加索引。如果数据是9行9位数字,则最终将有9 单元格grid尚未初始化,并且一旦完成内部两个 ,则尚未从该文件中读取9个字符 迭代。所以你会再次进入外部循环,阅读这些 字符。其中一些将是数字,因此您最终会覆盖grid中的 单元格,您已经写入了—这可能是您观察的 效果。此外,一旦你到达文件的末尾, file.get()将开始返回EOF —通常为-1。毫无疑问,这是 为什么你的测试'\n''\r'没有奏效。

而这些只是格式正确的文件的问题。对于 格式正确的文件,只需使用file >> n,与char 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"); 
}