为什么std::cin不能正确读取我的输入?

  • 本文关键字:读取 std cin 不能 c++
  • 更新时间 :
  • 英文 :


我正在用下面的代码为我的c++类做一个作业:

#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
string fileName;
string cheek,s;
long count;
ifstream input;
bool ask=1;
int main(){
while(ask){
cout<<"Enter a filename :n";
cin>>fileName;
cout<<"reading file...";
input.open(fileName);
if(input){
ask=0;
}
}
istringstream iss;
cout<<"dumping contents...";
while(getline(input,cheek)){
//
}
iss.str(cheek);
cout<<"parsing...";
while(iss.peek()!=EOF){
s=iss.peek();
if(s=="A"||s=="E"||s=="I"||s=="O"||s=="U"||s=="a"||s=="e"||s=="i"||s=="o"||s=="u"){
count++;
}
}
cout<<"nCOUNT="<<count<<"nresetting...n";
count=0;
iss.str("");
input.close();
fileName="";
cheek="";
s="";
}

由于某种原因,cin无法识别当我清楚地按Enter键时。有解决这个问题的方法吗?

while(getline(input,cheek)){

只要while循环条件计算为逻辑true,这个while循环将继续运行。每次调用getline()时,读取文件中的下一行,并且getline()返回true。到达文件末尾后,getline()最终返回false。

循环本身似乎没有发生任何事情:

//
}

就是这样。这就是整个循环。所以,用你自己的话,你能描述一下在这个循环中发生了什么吗?您可以给出的唯一答案是:在存储在cheek变量中之后,已经读取了整个文件,并将其内容逐行丢弃。由于std::getline所做的第一件事是擦除它作为参数获得的字符串,因此在整个过程结束时,您将始终以空cheek结束,并且整个文件已被完全读取。

在这个循环之后,有一些代码似乎认为cheek中有一些值得探索的东西,但是,由于上面概述的原因,那里没有任何东西。

这就是为什么所显示的代码没有完成任何任务。看起来您希望将后续逻辑放在while循环,而不是在它后面。要做到这一点,你所要做的就是遵循计算机编程的黄金法则:你的计算机总是精确地执行你让它做什么,而不是你想让它做什么"根据这条规则,您所要做的就是将逻辑的适当部分移到while循环本身中。

除了Sam回答中提到的问题之外,您还有许多其他问题。避免使用global变量。相反,声明所需范围内的所有变量。例如,你可以在main()中包含所有的值,在while (getline ...循环中包含一些值,例如

#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main(){
string fileName;
string cheek;
long count = 0,       /* count must be initialized */
line = 0;
ifstream input;

正如评论中提到的,您的ask变量是多余的。这没有错,但是你可以简单地通过不断循环来完成同样的事情,然后在收到良好的输入时break读取循环,例如

while (true) {
cout << "Enter a filename : ";
cin >> fileName;
cout << "reading file...n";
input.open(fileName);
if (input){
break;
}
}

你的文件读取循环是相当笨拙的。您的循环条件是正确的,但是最好只是检查每行中的字符。您可以使用istringstream,但不使用peek(),而是简单地提取一个字符,然后根据元音列表检查该字符,例如

cout << "dumping contents...n";

while (getline(input, cheek)) {
char c;
istringstream iss (cheek);
cout << "parsing line " << (line++) << 'n';
while (iss >> c) {
if (c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U' || 
c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
count++;
}
}
}

你不会真的"抛弃";任何文件内容。如果您想转储每一行输入,请添加:

cout << input << 'n';

cout << "parsing line ...之前的文件读取循环中。

注意,增加了一个line计数器,允许您报告检查的行数以及发现的元音数。行计数器可以用作简单的调试工具,以确认每行的解析,然后在不再需要时删除。最终输出可以是:

cout << "nLINES = " << line << "  COUNT = " << count << 'n';
}

没有理由关闭文件或重置变量,因为您没有循环从另一个文件读取。

示例输入文件

$ cat dat/fleas2line.txt
my dog has fleas
my cat has none

使用/输出示例

$ ./bin/dumpfile
Enter a filename : dat/fleas2line.txt
reading file...
dumping contents...
parsing line 0
parsing line 1
LINES = 2  COUNT = 8

虽然在这个简短的赋值中没有什么区别,但请确保您阅读并理解为什么"使用命名空间std;"被认为是不好的实践?

如果你还有问题,请告诉我。完整的源代码如下:
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main(){
string fileName;
string cheek;
long count = 0,       /* count must be initialized */
line = 0;
ifstream input;

while (true) {
cout << "Enter a filename : ";
cin >> fileName;
cout << "reading file...n";
input.open(fileName);
if (input){
break;
}
}

cout << "dumping contents...n";

while (getline(input, cheek)) {
char c;
istringstream iss (cheek);
cout << "parsing line " << (line++) << 'n';
while (iss >> c) {
if (c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U' || 
c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
count++;
}
}
}

cout << "nLINES = " << line << "  COUNT = " << count << 'n';
}

最新更新