2016-12-30 63 views
1

假設我正在讀取一個文件(「infile.txt」是特定的)來計算測驗得分的平均值。正被讀取的文件如下:在無故讀取文件時跳過C++行

塞巴斯蒂安插孔40 50 60 72 39 67 85 10 92 83

利克丹48 19 2 3 29 10 60 72 83 91

鏗瑤48 30 68 27 94 81 20 38 90 81

甲板浩91 82 65 55 79 93 89 19 23 37

輸出到另一個文件是通過增加另一個INT數,這是AVE每個學生的得分都很高。然而,第二和第四名學生被無緣無故地跳過。下面是輸出:

塞巴斯蒂安插孔40 50 60 72 39 67 85 10 92 83 59.8

鏗瑤48 30 68 27 94 81 20 38 90 81 57.7

這是我的代碼:

// This is a program that will output the average quiz score of all student, 
based on the student score file 

#include <iostream> 
#include <fstream> 
#include <string> 

int main() 
{ 
    using namespace std; 

    ifstream inf; 
    ofstream outf; 

    inf.open("infile.txt"); 
    outf.open("outfile.txt"); 

    string name; 
    int score, total; 
    double average; 
    char next; 
    while (inf >> name) { 
     total = 0; 

     outf << name << ' '; 
     inf >> name; 
     outf << name << ' '; 

     while (inf >> score) { 
      total += score; 
      outf << score << ' '; 
     } 
     average = total/10.0; 
     outf << average << endl; 

     inf.clear(); 
     inf.ignore(numeric_limits<streamsize>::max(), '\n'); 
    } 

    inf.close(); 
    outf.close(); 
    return 0; 
} 

有沒有我的代碼錯誤?非常感謝!

+3

「有我的代碼的任何錯誤?」是。考慮用'getline'來讀取單獨的行。你有一個squirrely while循環。 – AndyG

+2

'忽略'每隔一行就扔掉。註釋,並寫出所有行。 – wally

+0

如果您的代碼有效,您可能需要發送到[email protected] –

回答

3

我認爲功能ignore(numeric_limits<streamsize>::max(), '\n');是忽略,直到它得到另一個'\n',儘量不要使用它。

+0

非常感謝!輸出文件在我刪除代碼後正確完成。 我包含代碼的原因是因爲最初我只能讀取文件的一行,而我無法找到該錯誤。然後我試着添加這個函數來檢查''\ n''以進入下一行。 – ViktorHerald

4

Jaspreet的建議是正確的;我會添加一些背景。

您的程序邏輯是讀取數據的一種有效方法。 (另一種可能性,對於面向行的「記錄」數據通常更直觀,是逐行讀取並單獨解析每行,這使得每個「記錄」的末尾顯而易見。)

現在爲什麼是ignore()跳行?原因是空行已經被跳過了。詳細信息:

您的算法嘗試讀取數字,直到失敗,因爲下一個單詞不是數字(或因爲已達到EOF)。現在讀取數字的庫邏輯首先跳過任何主要的空白,包括換行符;你現在看到了問題。只有讀取下一個名字的第一個字母后,數字讀取算法纔會放棄,並將讀取的字母放回到輸入中。跳過的換行符不會退回。然後來到您的ignore並跳過我們站在開頭的有效線。

好消息是,對於內部結構顯示記錄邊界(如:記錄以數字序列結束;第一個非數字表示新記錄開始處)的記錄,您可以忽略任何空白行打破並且一字一句地解析。這使程序更健壯:您可以在沒有空行或多空行的情況下處理數據,或根本沒有任何換行符!

如果儘管數據可能包含偶然錯誤(例如數字中的一個字母),但仍然可以將這些換行符用作可以嘗試重新同步的位置,這是通過強大的編程實現的。但在你的情況下,重新同步會自動發生(可能是在讀了一個嚴重分析過的「記錄」,其中有一個名字帶有一個數字)。

作爲最後討論細點,我建議從標準輸入讀取和寫入這種類型的數據處理到stdout;將數據源和目的地留給呼叫者(通過myprog <infile.txt> outfile.txt等)。 Windows和* nix命令行都支持這一點。這使得該程序更加通用並且節省了編程工作。如果分配要求要讀取的兩個文件,對上述數據中分離的實際算法工作(解析記錄並計算平均值)從獲取和編寫數據,這應該是在剛得到一個IStream功能和ostream。這將使得可以通過任何來源提供數據,例如字符串,通過串流。

事實上,人們可以通過定義一個與數據記錄相對應的類,併爲它重載operator>>,以及一個float record.averageScore()成員函數:-)來分離算法工作。這看起來更像C++。

這裏有什麼可能工作幾個片斷。 playerT是一個擁有「記錄」數據的類。我實現了輸入函數,因爲清除輸入流的失敗位有點棘手。

/// Currently just a first name, family name and vector of scores 
class playerT 
{ 
    string firstName; 
    string lastName; 
    vector<float> scores; 
public: 
    float averageScore() 
    { 
     return scores.size() 
         ? accumulate(scores.begin(), scores.end(), 0.0)/scores.size() 
         : 0; // avoid dividing by zero. 
    } 

    friend ostream & operator<<(ostream &os, const playerT &player); 
    friend istream &operator>>(istream &is, playerT &player); 
}; 

/// Produces output which could be read back with 
/// the input operator. In particular, does not 
/// output the average. 
ostream &operator<<(ostream &os, const playerT &player) 
{ 
    //... 
} 

// Error handling is left to the caller. 
// In particular, after EOF the player must be tested for completeness. 
istream &operator>>(istream &is, playerT &player) 
{ 
    is >> player.firstName >> player.lastName; 

    player.scores.clear(); 
    float nextScore; 
    while(is >> nextScore) 
    { 
     player.scores.push_back(nextScore); 
    } 

    // Clear the expected format error indicating end of scores 
    // (and therefore this record), 
    // but not others which must be handled by the caller. 
    is.clear(is.rdstate() & ~ios::failbit); 
    return is; 
} 

主要功能歸結爲很少,這使得信息流更清晰。原因是像清除失敗位等髒I/O細節被轉移到專門的功能,以及計算平均值的「業務邏輯」。

int main() 
{ 
    do // loop to eof 
    { 
     playerT newPlayer; 

     cin >> newPlayer; 
     // if this was the last record eof is now true 
     // and the loop will exit after printing the last record. 

     // todo: handle I/O errors 
     cout << newPlayer << " (Av.: " << newPlayer.averageScore() << ')' << endl; 
    }while(cin.good()); 

    return cin.bad(); // eof is ok. only bad is bad. 
} 
+0

非常感謝!我已經通過做Jaspreet建議做的事來解決問題。我將在稍後閱讀您的文章以獲取更多信息,因爲我還沒有學過課程和對象。 – ViktorHerald

相關問題