上代码:
//读取用户输入,到某一个字符为止,并计数 #include<iostream> int main() { using namespace std; char word; //char类型,决定一次只能读取一个字符 int a = 0; cout << "Enter a word and end with '#': " << endl; cin >> word; //因为类型为char,所以cin只读取了用户输入的第一个字符,其余字符还在缓冲区之中,未被读取 cout << "你输入的是 "; while (word != '#') //注意,不能用空字符\0来替代 { cout << word; //先输出用户输入的第一个字符 ++a; //为了防止用户无输入字符,因此a初始化为0,如果能执行这个循环,说明至少用户输入了一个字符,那么++a则让a为1,a用于计数用户输入了多少个字符 //a的值等同于执行了多少遍循环。另a++等价。因为无需输出a,a++和++a都是a+1 cin.get(word); //将缓存区中的字符,每次赋值一个给word。一直赋值到缓存区没有字符为止。 //cin>>word; 假如使用这一行代码替代上面那行代码的话,将无法读取输入的空格、tab或者换行符了(换行符为最后一个字符除外) } cout << " 对吧。共计有" << a << "个字符(包含空格等字符)。" << endl; system("Pause"); return 0; }
输出:
Enter a word and end with '#': wang dong# 你输入的是 wang dong 对吧。共计有9个字符(包含空格等字符)。 请按任意键继续. . .
总结:
①利用char类型一次只能读取一个字符的特点,逐个读取用户输入(后放到缓存区)的字符。
②每次读取后,{将读取的字符输出,然后再次读取下一个}这样的循环形式。
以读取到‘#’字符,判断是否结束循环。
因此读取到#字符,所以可以无需再次输出字符(此时若输出,则输出的是#字符)。
③每次执行循环——即读取到一个非#字符,
则记录读取字符数的变量+1。
++a也可以写成a++,或者a=a+1
④程序的逻辑是这样的(无说明,则按顺序向下执行):
(1)要求用户输入一个字符;
(2)用户是否输入字符,未输入跳(2.1),输入跳(3)
(2.1)cin只读取非空格/换行/tab字符,要求用户继续输入。没输入继续跳(2.1),输入了跳(3)
(3)将用户输入的存储到缓存区,然后被cin读取一个字符;
(4)进入while部分,先判断,读取的是否是#字符,是,跳(end),不是,跳(5)
(5)输出读取的字符;
(6)计数器+1——因为读取到一个非#字符;
(7)读取下一个字符,若读取不到,则要求用户输入字符,跳(4)
(end)输出计数器的数字(读取到的非#的字符的数量),且此时已经输出了#前的所以字符。
假如用户输入了几个字符,但未输入#字符,那么先正常执行,到读取不到字符为止,此时是(7),要求用户继续输入字符,假如用户没输入#,输入了其他,继续循环(4)~(7),假如输入了#字符,跳到(4)后结束循环,跳到(end)。
注:问题在于,用户若未按要求输入#作为结尾,计数器没问题,但最后排版会出问题。
舍弃掉缓存区无用的字符(剩余的所有字符)
⑤假如需要两次判断这些语句。而用户又输入了比如abc#def。那么在读取完abc#后,def依然留在缓存区之中。
如果需要第二次判断,那么就需要用一个getline(cin,string类型变量名),读取掉缓存区的所有字符,只剩下最后的换行字符。然后,第二次可以如同这样继续。
之所以用getline,和string类型,是因为只有这样才能确保读取掉缓存区所有字符(包括空格,换行符等)而cin>>则不会读取空格,换行符等,假如剩余字符中有这些字符,那么就不会读取完所有字符。
例如,用户输入abc#def,
第一次判断读取到abc#,然后缓存区剩下def。
于是,第二部分,直接读取了def,还有f后面的换行符(即4个字符),然后发现没有#作为结尾,要求用户继续输入。
于是,加入两行代码:
string ddd; //string类型变量ddd,用于读取不符合要求的信息
getline(cin,ddd); //读取掉缓存区剩余的所有字符,包括最后的换行符也舍弃掉。
这两行代码读取掉了def,和最后的换行符。
在进入下一部分正常读取之后,cin发现缓存区无东西可读,于是要求用户输入字符。
于是就进入了正常循环之中。
如代码:
//读取用户输入,到某一个字符为止,并计数。此种行为重复两次 #include<iostream> #include<string> int main() { using namespace std; char word; //char类型,决定一次只能读取一个字符 int a = 0; cout << "Enter a word and end with '#': " << endl; cin >> word; //因为类型为char,所以cin只读取了用户输入的第一个字符,其余字符还在缓冲区之中,未被读取 cout << "你输入的是 "; while (word != '#') //注意,不能用空字符\0来替代 { cout << word; //先输出用户输入的第一个字符 a++; //为了防止用户无输入字符,因此a初始化为0,如果能执行这个循环,说明至少用户输入了一个字符,那么++a则让a为1,a用于计数用户输入了多少个字符 //a的值等同于执行了多少遍循环 cin.get(word); //将缓存区中的字符,每次赋值一个给word。一直赋值到缓存区没有字符为止。 //cin>>word; 假如使用这一行代码替代上面那行代码的话,将无法读取输入的空格、tab或者换行符了(换行符为最后一个字符除外) } cout << " 对吧。共计有" << a << "个字符(包含空格等字符)。" << endl; string ddd; //string类型变量ddd,用于读取不符合要求的信息 getline(cin,ddd); //读取掉缓存区剩余的所有字符,包括最后的换行符也舍弃掉。 char word1; //char类型,决定一次只能读取一个字符 int b = 0; cout << "Enter a word and end with '#': " << endl; cin >> word1; //因为类型为char,所以cin只读取了用户输入的第一个字符,其余字符还在缓冲区之中,未被读取 cout << "你输入的是 "; while (word1 != '#') //注意,不能用空字符\0来替代 { cout << word1; //先输出用户输入的第一个字符 b++; //为了防止用户无输入字符,因此a初始化为0,如果能执行这个循环,说明至少用户输入了一个字符,那么++a则让a为1,a用于计数用户输入了多少个字符 //a的值等同于执行了多少遍循环 cin.get(word1); //将缓存区中的字符,每次赋值一个给word。一直赋值到缓存区没有字符为止。 //cin>>word; 假如使用这一行代码替代上面那行代码的话,将无法读取输入的空格、tab或者换行符了(换行符为最后一个字符除外) } cout << " 对吧。共计有" << b << "个字符(包含空格等字符)。" << endl; system("Pause"); return 0; }
输出:
Enter a word and end with '#': a b # c d # e f# 你输入的是 a b 对吧。共计有4个字符(包含空格等字符)。 Enter a word and end with '#': b c# 你输入的是 b c 对吧。共计有3个字符(包含空格等字符)。 请按任意键继续. . .
注意:输出第三行的b后面有一个空格字符,其他是排版预留的空格字符。
EOF:
还是没搞懂,大概总结总结吧。
EOF是文件尾,
很多操作系统都支持用键盘模拟文件尾(比如window是ctrl+z)。
编译器检测到文件尾之后,cin将(eofbit和failbit)设为1。然后可以通过eof()来查看eofbit是否为1。如果是1,则eof()返回true。
cin.eof()则是检测cin输入的内容的eof是不是为1。
当cin.eof()检测到EOF后,于是将返回true
若和其他字符一起输入,ctrl+z不会被认为是EOF(比如我输入abc然后ctrl+z回车,输出的是abc和->,->是一个字符) ,只有单独输入的时候,才会被认为是EOF。然后cin.eof()==true了。
检测到eof后,cin将不再读取输入了。
部分系统可以用cin.clear()来清理掉eof标记。从而cin可以继续读取输入。
在while(cin)这行代码里,cin是检测是否能读取——或者说是否遇见文件尾,没遇见,则能读取,返回值true——继续循环。遇见,不能读取,返回false(0),停止循环。
————注意,判断语句实际上是根据表达式的返回值,为true则执行循环,否则停止。
循环语句也可以改为:
char word; //char类型,决定一次只能读取一个字符 int a = 0; cout << "Enter a word and end with '#': " << endl; while (cin.get(word))a++;
效果同之前的。即:
(1)读取缓存区,赋值给word变量(cin.get(word);
(2)能读取,返回值true,执行循环体(a++),循环体也可以为空;
(3)不能读取,返回值flase(需要通过ctrl+z来关闭cin,才不能读取);
(4)假如没有遇见eof,那么cin.get(word)要求用户继续输入。
不用eof的话,改为代码:
//效果是遇见换行符停止读取,并输出字符 int a = 0; cout << "Enter a word and end with : " << endl; while (cin.get(word)) { if (word == 10)break; cout << word; a++; }
注:
①word=10表示遇见换行符(ASCII值为10)执行后面的循环语句。
②if (word == 10)break;这行代码的意思是,当检测到输入的字符为换行符时,破坏循环(即结束循环)。
③break是退出当前循环(注意,if这一行语句不是循环)。即结束while这一个循环。但不结束所有循环。
且break语句后面的循环都不再执行。
EOF在判断语句的时候,可以直接用不带双引号的“EOF”作为判断语句,例如
while(word!=EOF){},则是word读取到的字符不是EOF的时候,则执行循环,读取到EOF,则停止循环。——!=表示不等于
有时候,char类型不支持,需要改为:
int a; //事先声明一个int变量a char word; //char类型word变量用于读取字符 while ((a=word)!=EOF){}
效果同上面
但总的来说!!对EOF还是很晕啊!!!!
cin的几个变种:
①假如首先char a;
然后a=cin.get()和cin.get(a)是一样效果的。
②假如char a变为int a,那么cin.get(a)就无法使用了。而a=cin.get()是可以使用的,但是返回的是int值(因为a是int类型);