谁能告诉我我做错了什么(cpp)用getline格式化

Can anybody tell me what I did wrong (cpp) formatting with getline

正在尝试使用 C++ getline 函数进行格式化。输出将所有内容放在第一个记录编号 forename 而不是它应该去的地方。

代码:

#include <fstream>
#include <string>
#include <iostream>
using namespace std;

int main()
{
    const int RANGE = 12;
    string tab[RANGE];
    int i = 0, j = 0;
    ifstream reader("records.txt");
    if (!reader)
    {
        cout << "Error opening input file" << endl;
        return -1;
    }
    while (!reader.eof())
    {
        if ( ( i + 1) % 4 == 0)
            getline( reader, tab[i++], '\n');
        else
            getline( reader, tab[i++], '\t');
    }
    reader.close();
    i = 0;
    while (i < RANGE)
    {
        cout << endl << "Record Number: " << ++j << endl;
        cout << "Forename: " << tab[i++] << endl;
        cout << "Surname: " << tab[i++] << endl;
        cout << "Department: " << tab[i++] << endl;
        cout << "Telephone: " << tab[i++] << endl;
    }
    return 0;
}

TXT 文件内容:

John    Smith    Sales    555-1234
Mary    Jones    Wages    555-9876
Paul    Harris   Accts    555-4321

请 运行 代码让您自己了解发生了什么,并将 txt 文件放在与您的代码相同的文件夹中。

希望有人能帮助我谢谢。

有更简单的方法来分隔 istream 中的单词,即 C++ sring 流工具:

#include <fstream>
#include <iostream>
#include <sstream>  //<-- string stream library

using namespace std; //<-- should not be used, use scope std::

int main() {

    const int RANGE = 12;
    string tab[RANGE];
    string temp;       //<--to store each field temporarily
    int i = 0, j = 0;
    ifstream reader("records.txt");
    if (!reader) {
        cout << "Error opening input file" << endl;
        return -1;
    }
    while (getline(reader, temp)) { //<-- read one full line
        stringstream ss(temp); // <-- input to a string stream
        while(ss >> tab[i]){   // <-- passing strings to the string array one by one
            i++;
        }
    }
    reader.close();
    i = 0;
    while (i < RANGE) {
        cout << endl << "Record Number: " << ++j << endl;
        cout << "Forename: " << tab[i++] << endl;
        cout << "Surname: " << tab[i++] << endl;
        cout << "Department: " << tab[i++] << endl;
        cout << "Telephone: " << tab[i++] << endl;
    }
    return 0;
}

这里的想法是尽可能少地扰乱您的代码,我建议的一件事是使用 std::vector 而不是普通的固定大小数组。另外,正如所说和链接的那样,eof 非常不可靠。

Why is iostream::eof inside a loop condition (i.e. while (!stream.eof())) considered wrong?

此外,如果文件少于 12 个字符串,您的最终 while 循环应该只输出实际读入数组的字符串,而不是整个数组。但是除非你能保证你的文件永远不会超过 12 个字符串,否则你应该使用 std::vector 而不是固定数组。

此外,我不会在单个循环中交替使用 getline() 定界符,而是使用外部循环仅读取整行,然后分别从每行中读取制表符分隔的值。然后将值存储在 array/vector 结构中,而不是单独存储。

试试像这样的东西:

#include <fstream>
#include <sstream>
#include <string>
#include <iostream>
#include <vector>
using namespace std;

struct Person
{
    string foreName;
    string surName;
    string department;
    string phoneNumber;
};

int main()
{
    ifstream reader("records.txt");
    if (!reader)
    {
        cout << "Error opening input file" << endl;
        return -1;
    }

    vector<Person> people;
    string line;

    while (getline(reader, line))
    {
        istringstream iss(line);
        Person p;
        getline(iss, p.foreName, '\t');
        getline(iss, p.surName, '\t');
        getline(iss, p.department, '\t');
        getline(iss, p.phoneNumber, '\t');
        people.push_back(p);
    } 

    reader.close();

    int j = 0;
    for (Person &p : people)
    {
        cout << endl << "Record Number: " << ++j << endl;
        cout << "Forename: " << p.foreName << endl;
        cout << "Surname: " << p.surName << endl;
        cout << "Department: " << p.department << endl;
        cout << "Telephone: " << p.phoneNumber << endl;
    }

    return 0;
}

我认为您的问题的根源在 Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong? 中有解释。

由于该错误,您正在阅读 tab[12]tab[13]tab[13]tab[14]。当然,这会导致未定义的行为。

将循环更改为:

// Read the contents of the file line by line
std::string line;
while (getline( reader, line))
{
   // Process each line's contents.
   std::istringstream str(line);
   getline(str, tab[i++], '\t');
   getline(str, tab[i++], '\t');
   getline(str, tab[i++], '\t');
   getline(str, tab[i++], '\n');
}

确保添加

#include <sstream>

要加倍确保您没有使用越界索引来使用数组,请添加检查。

while ( i+4 < RANGE && getline( reader, line))
{
   ...
}

首先,while (!reader.eof()) is not doing the right thing

您看到的直接问题是由于您的文件不包含 '\t',因此第一个 getline 已经将文件的所有内容读入 tab[0] . (至少那是我一对一复制你的文件内容后得到的)

您的代码相当困难,因为您在使用变量之前很久就声明了变量,然后又重用了它们。您有一个固定大小的数组,但是当文件中有更多行时,您的代码就会崩溃。将所有内容读入一个普通的字符串数组也会使事情变得复杂。访问 forename 或其他字段需要您计算数组中的偏移量。最好使用一种数据结构:

struct file_entry {
    std::string first_name;
    std::string last_name;
    std::string departure;
    std::string phone;
};

然后你可以定义一个输入运算符:

std::istream& operator>>(std::istream& in,file_entry& fe) {
    return in >> fe.first_name >> fe.last_name >> fe.departure >> fe.phone;
};

并使用 std::vector 存储与文件中一样多的条目:

int main() {
    std::string contents{"John    Smith    Sales    555-1234\n"
                         "Mary    Jones    Wages    555-9876\n"
                         "Paul    Harris   Accts    555-4321\n"};

    std::stringstream reader{contents};
    std::vector<file_entry> data;    
    std::string line;
    while (std::getline(reader,line)) {
        file_entry fe;
        std::stringstream{line} >> fe;
        data.push_back(fe);
    }

    for (const auto& fe : data) {
        std::cout << "Forename: " << fe.first_name << '\n';
        std::cout << "Surname: " << fe.last_name << '\n';
        std::cout << "Department: " << fe.departure << '\n';
        std::cout << "Telephone: " << fe.phone << '\n';
    }
}

live example

PS 你不需要在文件上调用 close,这已经在它的析构函数中完成了。不显式调用它的好处是,适用于文件流的相同代码也适用于字符串流。