谁能告诉我我做错了什么(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';
}
}
PS 你不需要在文件上调用 close
,这已经在它的析构函数中完成了。不显式调用它的好处是,适用于文件流的相同代码也适用于字符串流。
正在尝试使用 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';
}
}
PS 你不需要在文件上调用 close
,这已经在它的析构函数中完成了。不显式调用它的好处是,适用于文件流的相同代码也适用于字符串流。