2017-06-22 42 views
5

注意:請在回答之前閱讀評論。這個問題似乎是編譯器特定的。爲什麼iostream會在某些字中切斷第一個字母?

我有一個簡單的程序讀取一個名稱,並從文件或控制檯到一個struct Student_info一些成績,然後通過重載< <和>>運算打印出的一些數據。然而,該計劃正在切斷部分甚至整個單詞並轉移數據。例如,輸入

Eunice 29 87 42 33 18 13 
Mary 71 24 3 96 70 14 
Carl 61 12 10 44 82 36 
Debbie 25 42 53 63 34 95 

返回

Eunice: 42 33 18 13 
Mary: 3 96 70 14 
rl: 10 44 82 36 
25: 63 34 95 

表明不知何故,流已經忽略卡爾的前兩個字母,然後轉移整個流離開1個字。我一直試圖在一個小時內調試它,但似乎是任意的。對於不同的名字,不同的單詞被切斷,沒有明顯的模式。

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

struct Student_info { 
    friend std::ostream &operator<<(std::ostream &output, 
            const Student_info &S) { // overloads operator to print name and grades 
     output << S.name << ": "; 
     for (auto it = S.homework.begin(); it != S.homework.end(); ++it) 
      std::cout << *it << ' '; 
     return output; 
    } 

    friend std::istream &operator>>(std::istream &input, Student_info &S) { // overloads operator to read into Student_info object 
     input >> S.name >> S.midterm >> S.final; 
     double x; 
     if (input) { 
      S.homework.clear(); 
      while (input >> x) { 
       S.homework.push_back(x); 
      } 
      input.clear(); 
     } 
     return input; 
    } 

    std::string name; // student name 
    double midterm, final; // student exam scores 
    std::vector<double> homework; // student homework total score (mean or median) 

}; 


int main() { 
    //std::ifstream myfile ("/Users/.../Documents/C++/example_short.txt"); 
    Student_info student; // temp object for receiving data from istream 
    std::vector<Student_info> student_list; // list of students and their test grades 
    while (std::cin >> student) { // or myfile >> student 
     student_list.push_back(student); 
     student.homework.clear(); 
    } 
    for (auto it = student_list.begin(); it != student_list.end(); ++it) { 
     std::cout << *it << '\n'; 
    } 
    return 0; 
} 

編輯:添加換行符。

正如你可以看到它不與clang工作,但它與GCC

+3

用'getline()'將整行讀入一個字符串,然後使用'std :: stringstream'將其讀入結構成員。 – Barmar

+1

它在我的電腦上運行得非常好。 – Jiahao

+0

@ArnoldLayne Odd。我在XCode 8.3.3中編譯,[this](http://imgur.com/a/bxNvU)是輸出。 – JAustin

回答

8

當涉及到失敗的浮點格式化輸入時,它們如何實現標準的實現之間存在不一致。

clang(或更準確地說,libc++)會讀取並放棄有效浮點表示可能包含的所有字符,即使它不能包含在此位置並且轉換必然會失敗。這些字符包括CA(都是大寫和小寫,因爲它們是十六進制數字,標準實際允許使用十六進制浮點數符號)。因此,當試圖讀取double並且輸入包含Carl時,即使沒有浮點數字可以以這些字符中的任何一個開頭,也會讀取並丟棄字符CA

另一方面,gcclibstdc++)只要變得明確表示轉換失敗就會停止讀取。因此,如果輸入包含Carl,則轉換在第一個字符處停止(並保留在流中),因爲十六進制浮點數不能以C(必須以0X開頭)開頭。

我不會自願意見關於哪種實現方式是正確的。不管它是什麼,普通的代碼都應該避開語言的微妙和神祕的角落。如果學生記錄是一行,那麼代碼應該讀取行。如果學生記錄被定義爲「姓名和持續到下一個姓名的數字序列」,則停止並閱讀this article

+1

,現在我們需要一個冒險傢伙或加州大學潛入標準,並回到關於標準所說的內容的裁決。很好,順便說一句。 – bolov

+2

@bolov有[這個SO問題](https://stackoverflow.com/questions/24689378/characters-extracted-by-istream-double),探討這個問題,並有一些有趣的外部鏈接。 –

+0

這就是我一直在尋找的。鏈接的問題很好! –

1

做我認爲這個問題是在分析與end of linedouble輸入。 我找到了2種方法來解決它:

  1. 閱讀功課,直到行尾。

    friend std::istream &operator>>(std::istream &input, Student_info &S) 
    { // overloads operator to read into Student_info object 
        input >> S.name >> S.midterm >> S.final; 
        double x; 
        if (input) 
        { 
        S.homework.clear(); 
        while ((input.peek()!='\n') && input >> x) 
        { 
         //std::cout << x << "\n"; 
         S.homework.push_back(x); 
        } 
        input.clear(); 
        } 
    
        return input; 
    } 
    
  2. 不解析它爲雙如果你知道的投入將是整數

    friend std::istream &operator>>(std::istream &input, Student_info &S) 
    { // overloads operator to read into Student_info object 
        input >> S.name >> S.midterm >> S.final; 
        int x; 
        if (input) 
        { 
        S.homework.clear(); 
        while (input >> x) 
        { 
         //std::cout << x << "\n"; 
         S.homework.push_back(x); 
        } 
        input.clear(); 
        } 
    
        return input; 
    } 
    
1

當你知道的信息爲Student_Info對象總是在一個單一的線,它是更好地使用以下策略。

  1. 閱讀一行文字。
  2. 從文本行構建std::istringstream
  3. std::istringstream中提取對應於Student_Info的數據。

它只是使解析代碼更簡單,更不容易出錯。

// overloads operator to read into Student_info object 
friend std::istream &operator>>(std::istream &input, Student_info &S) 
{ 
    std::string line; 
    if (!getline(input, line)) 
    { 
     // Problem reading a line of text. 
     return input; 
    } 

    std::istringstream str(line); 

    str >> S.name >> S.midterm >> S.final; 
    S.homework.clear(); 
    double x; 
    while (str >> x) 
    { 
     S.homework.push_back(x); 
    } 
    return input; 
} 

FWIW,我不能重複你所看到的問題。查看http://ideone.com/13wHLa的工作版本。

+0

我沒有添加賞金,但請注意,問題似乎是編譯器特定的,因爲代碼在使用gcc編譯時工作,但不與clang編譯。 – JAustin

相關問題