2012-04-05 25 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"); 
}