使用 getline 处理重定向文件输入后使用 cin 进行键盘输入
Using cin for keyboard input after processing redirected file input with getline
我知道,这个问题已经被处理了很多次了..但我还是不能让它工作..我在这里粘贴一些代码:
#include <sstream>
#include "header.h"
using namespace std;
using namespace header;
int main(){
string parent, child, line, node;
int choose = 0;
tree_ptr tree_inst = new tree;
cout << "*** Start ***" << endl;
while (getline(cin, line, '\n')){
istringstream line_stream(line);
line_stream >> parent;
if (parent.compare("0") == 0) break;
while (line_stream >> child) {
if (!tree_inst->insert(parent, child)) {
cout << "*** ERROR! ***" << endl;
tree_inst->visit(tree_inst->root);
cout << "*** End ***" << endl;
return -1;
}
}
}
while (true) {
cin >> choose; //<== doesn't wait for the input, just loop forever
// on the default statement of the switch...
switch (choose) {
...
}
}
}
我已经尝试插入一些 cin.sync() cin.clear() cin.ignore() ..etc.. 但没有任何改变!
第一个 getline()
循环将永远循环下去,如果你不以某种方式打破它的话。如果以干净的方式完成,这根本不应该成为问题。事实上我无法重现你的错误。
如何分析错误
所以原因要么是 cin
的错误状态,要么是非数字非 space 输入仍在等待处理。为了帮助您找出答案,我建议您添加一些诊断代码:
cout << "Enter free lines of text or stop to return to the menu:";
while (getline(cin, line, '\n')) { // This would loop foreved
if (line == "stop") // I added this one to exit
break; // but how do you do ?
}
while (true) { // I get no problem here
cout << "Cin status: failed=" // <===Add this simple diagnostic to
<< cin.fail() << " bad=" // check the state of the stream
<< cin.bad() << " eof=" << cin.eof() << endl;
cout << "Next char in decimal is:" // <=== Add this to show
<< cin.peek() << endl; // where in the stream you're hanging
cout << "Choose:";
cin >> choose;
cout << "selected: " << choose << endl;
}
如果您的流状态不干净,尽管有 cin.clean()
,那是因为您关闭了流或在控制台输入了文件结束代码 (Ctrl+D 或 Ctrl+Z 取决于系统).
如果流状态是干净的,但 peeked 字符不是数字(即十进制代码不在 48 和 57 之间),这是将流设置为失败状态的错误输入。
编辑:您的具体情况
查看您提供的诊断(fail=1,eof=1),似乎在第一个循环之后您已经到达了输入的末尾。因此您的输入失败,因为没有进一步的数据可读。您在 pastebin 上的输入文件确认最后一行是您用来退出第一个循环的“0”。
经过我们的交流,我了解到您实际上已经从命令行重定向了输入(例如 yourprogramme <yourinput.txt
),并希望您的代码在重定向的文件输入结束后切换回键盘输入。不幸的是,这不是它的工作方式。如果您从文件重定向输入,cin
将始终引用重定向的文件。
为了能够混合文件和键盘输入,您需要使用 <fstream>
,更准确地说,ifstream
用于从文件读取,并保留 cin
用于键盘输入。
这里是一个稍微修改过的代码,它从命令行获取文件名但没有间接访问(例如 yourprogramme yourinput.txt
):
...
int main(int argc, char**argv)
{
if (argc != 2) { // if called from command line wrong arguments
cerr << "You must provide the name of the data file as command line argument\n";
return EXIT_FAILURE;
}
ifstream file(argv[1]); // open the file for reading
if (!file) { // if open failed, end the programme
cerr << "Could not open "<<argv[1]<<"\n";
return EXIT_FAILURE;
}
string line; // here your code from before
int choose = 0;
cout << "*** Loading "<<argv[1]<< " ***" << endl;
// but in the first loop replace cin with file
while (getline(file, line, '\n')){
cout << "Read: " << line<<endl;
if (line == "0") // Abridged version;-)
break;
}
file.close(); // File is no longer needed here.
while (true) { // Second loop, unchanged, using cin
cout << "Choose (9 to exit):";
if (!(cin >> choose)) // avoid looping forever if problem on cin
break;
cout << "selected: " << choose << endl;
if (choose == 9)
break;
}
return EXIT_SUCCESS;
}
我知道,这个问题已经被处理了很多次了..但我还是不能让它工作..我在这里粘贴一些代码:
#include <sstream>
#include "header.h"
using namespace std;
using namespace header;
int main(){
string parent, child, line, node;
int choose = 0;
tree_ptr tree_inst = new tree;
cout << "*** Start ***" << endl;
while (getline(cin, line, '\n')){
istringstream line_stream(line);
line_stream >> parent;
if (parent.compare("0") == 0) break;
while (line_stream >> child) {
if (!tree_inst->insert(parent, child)) {
cout << "*** ERROR! ***" << endl;
tree_inst->visit(tree_inst->root);
cout << "*** End ***" << endl;
return -1;
}
}
}
while (true) {
cin >> choose; //<== doesn't wait for the input, just loop forever
// on the default statement of the switch...
switch (choose) {
...
}
}
}
我已经尝试插入一些 cin.sync() cin.clear() cin.ignore() ..etc.. 但没有任何改变!
第一个 getline()
循环将永远循环下去,如果你不以某种方式打破它的话。如果以干净的方式完成,这根本不应该成为问题。事实上我无法重现你的错误。
如何分析错误
所以原因要么是 cin
的错误状态,要么是非数字非 space 输入仍在等待处理。为了帮助您找出答案,我建议您添加一些诊断代码:
cout << "Enter free lines of text or stop to return to the menu:";
while (getline(cin, line, '\n')) { // This would loop foreved
if (line == "stop") // I added this one to exit
break; // but how do you do ?
}
while (true) { // I get no problem here
cout << "Cin status: failed=" // <===Add this simple diagnostic to
<< cin.fail() << " bad=" // check the state of the stream
<< cin.bad() << " eof=" << cin.eof() << endl;
cout << "Next char in decimal is:" // <=== Add this to show
<< cin.peek() << endl; // where in the stream you're hanging
cout << "Choose:";
cin >> choose;
cout << "selected: " << choose << endl;
}
如果您的流状态不干净,尽管有 cin.clean()
,那是因为您关闭了流或在控制台输入了文件结束代码 (Ctrl+D 或 Ctrl+Z 取决于系统).
如果流状态是干净的,但 peeked 字符不是数字(即十进制代码不在 48 和 57 之间),这是将流设置为失败状态的错误输入。
编辑:您的具体情况
查看您提供的诊断(fail=1,eof=1),似乎在第一个循环之后您已经到达了输入的末尾。因此您的输入失败,因为没有进一步的数据可读。您在 pastebin 上的输入文件确认最后一行是您用来退出第一个循环的“0”。
经过我们的交流,我了解到您实际上已经从命令行重定向了输入(例如 yourprogramme <yourinput.txt
),并希望您的代码在重定向的文件输入结束后切换回键盘输入。不幸的是,这不是它的工作方式。如果您从文件重定向输入,cin
将始终引用重定向的文件。
为了能够混合文件和键盘输入,您需要使用 <fstream>
,更准确地说,ifstream
用于从文件读取,并保留 cin
用于键盘输入。
这里是一个稍微修改过的代码,它从命令行获取文件名但没有间接访问(例如 yourprogramme yourinput.txt
):
...
int main(int argc, char**argv)
{
if (argc != 2) { // if called from command line wrong arguments
cerr << "You must provide the name of the data file as command line argument\n";
return EXIT_FAILURE;
}
ifstream file(argv[1]); // open the file for reading
if (!file) { // if open failed, end the programme
cerr << "Could not open "<<argv[1]<<"\n";
return EXIT_FAILURE;
}
string line; // here your code from before
int choose = 0;
cout << "*** Loading "<<argv[1]<< " ***" << endl;
// but in the first loop replace cin with file
while (getline(file, line, '\n')){
cout << "Read: " << line<<endl;
if (line == "0") // Abridged version;-)
break;
}
file.close(); // File is no longer needed here.
while (true) { // Second loop, unchanged, using cin
cout << "Choose (9 to exit):";
if (!(cin >> choose)) // avoid looping forever if problem on cin
break;
cout << "selected: " << choose << endl;
if (choose == 9)
break;
}
return EXIT_SUCCESS;
}