2017-06-22 40 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

相关问题