(七十七)循环和文本输入、EOF

简介:

上代码:

//读取用户输入,到某一个字符为止,并计数
#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类型);




目录
相关文章
解决CodeBlock安装完成后不能进行注释和printf输出中文的解决方式
前几天重新用回CodeBlock发现编写注释后不能正常编译,修改后又不可以使用printf输出中文 现将解决方式记录备用
133 0
|
Shell
Shell 脚本输出命令结果保持原格式,保留换行
Shell 脚本输出命令结果保持原格式,保留换行
189 0
|
5月前
C primer plus 学习笔记 第13章 文件输入/输出
C primer plus 学习笔记 第13章 文件输入/输出
|
5月前
|
存储 C语言 知识图谱
C primer plus 学习笔记 第4章 字符串和格式化输入/输出
C primer plus 学习笔记 第4章 字符串和格式化输入/输出
|
6月前
|
存储 安全 C语言
C语言程序设计——格式输入函数scanf()
C语言程序设计——格式输入函数scanf()
|
缓存 安全 Linux
[oeasy]python0068_控制序列_清屏_控制输出位置_2J
[oeasy]python0068_控制序列_清屏_控制输出位置_2J
94 0
 [oeasy]python0068_控制序列_清屏_控制输出位置_2J
|
C++ Python
一分钟学Python| 变量与输入和输出
一分钟学Python| 变量与输入和输出
230 0
一分钟学Python| 变量与输入和输出