cinscanfgetsgetchar比较Word文件下载.docx
《cinscanfgetsgetchar比较Word文件下载.docx》由会员分享,可在线阅读,更多相关《cinscanfgetsgetchar比较Word文件下载.docx(19页珍藏版)》请在冰点文库上搜索。
![cinscanfgetsgetchar比较Word文件下载.docx](https://file1.bingdoc.com/fileroot1/2023-5/6/c43713ba-7733-4934-b8a8-af6ffcc59d83/c43713ba-7733-4934-b8a8-af6ffcc59d831.gif)
其实这里的10恰好是回车符!
这是因为scanf()和getchar()函数是从输入流缓冲区中读取值的,而并非从键盘(也就是终端)缓冲区读取。
而读取时遇到回车(\n)而结束的,这个\n会一起读入输入流缓冲区的,所以第一次接受输入时取走字符后会留下字符\n,这样第二次的读入函数直接从缓冲区中把\n取走了,显然读取成功了,所以不会再从终端读取!
这就是为什么这个程序只执行了一次输入操作就结束的原因!
-----|问题描述二:
(分析scanf()和gets()读取字符串)|-------首先我们看一下scanf()读取字符串的问题:
程序2:
#include<
intmain(){
charstr1[20],
str2[20];
scanf("
%s"
str1);
%s\n"
str2);
程序的功能是读入一个字符串输出,在读入一个字符串输出。
可我们会发现输入的字符串中不能出现空格,例如:
测试一输入:
Helloworld!
输出:
【分析】到此程序执行完毕,不会执行第二次的读取操作!
这个问题的原因跟问题一类似,第一次输入Helloworld!
后,字符串Helloworld!
都会被读到输入缓冲区中,而scanf()函数取数据是遇到回车、空格、TAB就会停止,也就是第一个scanf()会取出"
Hello"
,而"
world!
"
还在缓冲区中,这样第二个scanf会直接取出这些数据,而不会等待从终端输入。
测试二:
Hello[Enter]
Hello[输出]
world[Enter]
world[输出]【分析】程序执行了两次从键盘读入字符串,说明第一次输入结束时的回车符被丢弃!
即:
scanf()读取字符串会舍弃最后的回车符!
我们再看一下gets()读取字符串的情况:
用scanf来读取一个字符串时,字符串中是不可以出现空格的,一旦出现空格,后面的数据就会舍弃残留在缓冲区中。
其实有另外一个函数是可以接受空格的,那就是gets(),下面我们看一下这个函数的应用,我们把程序2改动一下:
程序3:
int
main()
{
char
str1[20],
str2[20];
gets(str1);
gets(str2);
return
0;
}
测试:
Hello
[输入]
[输出]
12345
[输入]
【分析】显然与上一个程序的执行情况不同,这次程序执行了两次从键盘的读入,而且第一个字符串取了Hello
接受了空格符,而没有像上一个程序那样分成了两个字符串!
所以如果要读入一个带空格符的字符串时因该用gets(),
而不宜用scanf()!
-------|问题描述三:
(getchar()暂停程序,查看程序执行结果)|-------
不知道大家有没有遇到过这样的问题,有的编译器程序执行完后的结果界面不会停下而是一闪就没了,以至于看不到执行结果。
所以很多人在程序最后加上getchar()语句,目的是想让程序执行完后停下来,等待从终端接收一个字符再结束程序。
可是发现有时候这样根本没用,程序照样跳出去了。
【分析】原因跟上面例子讲的一样,是因为输入缓冲区中还有数据,所以getchar()会成果读到数据,所以就跳出了!
【总结】
第一:
要注意不同的函数是否接受空格符、是否舍弃最后的回车符的问题!
读取字符时:
scanf()以Space、Enter、Tab结束一次输入,不会舍弃最后的回车符(即回车符会残留在缓冲区中);
getchar()以Enter结束输入,也不会舍弃最后的回车符;
读取字符串时:
scanf()以Space、Enter、Tab结束一次输入
gets()以Enter结束输入(空格不结束),接受空格,会舍弃最后的回车符!
第二:
为了避免出现上述问题,必须要清空缓冲区的残留数据,可以用以下的方法解决:
方法1:
C语言里提供了函数清空缓冲区,只要在读数据之前先清空缓冲区就没问题了!
这个函数是fflush(stdin)。
方法2:
自己取出缓冲区里的残留数据。
(说实话这个语句我也没看懂,呵呵!
为什么格式控制是这样的!
希望高手指点一下!
)
%[^\n]"
string);
C/C++学习笔记2-cin深入分析(上)-
cin输入操作处理cin<
<
cin.get,cin.getline等函数深入分析很多初学者都认为cin函数是一个很简单的函数,其实不然!
cin函数有很多需要了解的知识(比如:
cin的返回值是什么,cin提供了哪些成员函数且分别是什么作用,如cin.clear(),cin.ignore(),cin.fail(),cin.good()等等),如果没有很好的掌握,在使用的时候很可能会出问题却不知其原因!
而且很多人也确确实实遇到过不少问题,以下是几个简单的例子:
程序1:
iostream>
usingnamespacestd;
intmain(){
intm,n;
cin>
>
m;
n;
测试情况:
如果用户每次都输入两个合法的数,程序不会出问题!
但是如果用户第一次输入时给一个非法的输入,比如说输入一个字符'
,你会发现程序不会再执行第二条输入语句。
似乎有点奇怪!
!
程序2:
charstr[8];
cin.getline(str,5);
cout<
str<
endl;
程序的功能很简单,就是输入一个字符串再输出,再次输入一个字符串输出。
程序执行情况:
测试一:
abcd(回车)abcd(输出)
efgh
(回车)
(输出)
当用户第一次输入的字符串字符数小于4时,程序执行正常!
测试二:
abcdefgh
abcd
(输出-换行)
当用户第一次输入的字符数字符数大于4时,第一个字符串接受输入的前四个字符,而第二次的输入操作没有执行,第二个字符串输出为空。
似乎也很奇怪!
其实在很多时候都会遇到诸如此类的问题,如果不熟悉程序输入的原理和cin等一些函数的原理就不知道怎么解决!
我在这里做一个简单的介绍,也许介绍得不是很准确和全面,或者存在一些误解,请大家包涵!
输入操作的原理
与前一节中提到的scanf函数一样,程序的输入都建有一个缓冲区,即输入缓冲区。
cin的一些输入函数和操作符
cin
is
a
extern
istream
object。
提供了很多可用的成员函数和重载的操作符,如:
cin<
cin.get(),
cin.getline()等。
下面我们来了解一下这几个函数:
一.
该操作符是根据后面变量的类型读取数据。
输入结束条件
:
遇到Enter、Space、Tab键。
(这个很重要!
)
对结束符的处理
丢弃缓冲区中使得输入结束的结束符(Enter、Space、Tab)
读字符的情况:
程序3:
#include
using
namespace
std;
c1,
c2;
c1;
c1<
c2<
a[Enter]
b[Enter]
输出:
b
测试二输入:
ab[Enter]
ab读字符串的情况:
程序4:
charstr1[10],str2[10];
str1;
str2;
str1<
str2<
abcd[Enter]
efgh[Enter]
abcd
efgh
【分析】输入遇到回车符结束,很正常。
abcdefgh
【分析】第一次读取字符串时遇到空格则停止了,将abcd读入str1,并舍弃了空格,将后面的字符串给了第二个字符串。
这证明了cin读入数据遇到空格结束;
并且丢弃空格符;
缓冲区有残留数据室,读入操作直接从缓冲区中取数据。
2.cin.get()
该函数有三种格式:
无参,一参数,二参数
即cin.get(),cin.get(charch),cin.get(array_name,Arsize)读取字符的情况:
输入结束条件:
Enter键对结束符处理:
不丢弃缓冲区中的Entercin.get()与cin.get(charch)用于读取字符,他们的使用是相似的,即:
ch=cin.get()与cin.get(ch)是等价的。
程序5:
cin.get(c1);
cin.get(c2);
//
打印两个字符
(int)c1<
(int)c2<
打印这两个字符的ASCII值
97
10
【分析】会发现只执行了一次从键盘输入,显然第一个字符变量取的'
第二个变量取的是Enter(ASCII值为10),这是因为该函数不丢弃上次输入结束时的Enter字符,所以第一次输入结束时缓冲区中残留的是上次输入结束时的Enter字符!
32
【分析】显然第一个字符变量取的'
第二个变量取的是Space(ASCII值为32)。
原因同上,没有丢弃Space字符。
读取字符串的情况:
cin.get(array_name,
Arsize)是用来读取字符串的,可以接受空格字符,遇到Enter结束输入,按照长度(Arsize)读取字符,
会丢弃最后的Enter字符。
程序6:
main
()
a[20];
cin.get(a,
10);
a<
abc
def[Enter]
def
【分析】说明该函数输入字符串时可以接受空格。
1234567890[Enter]
123456789【分析】输入超长,则按需要的长度取数据。
程序7:
intmain(){
charch,a[20];
cin.get(a,5);
ch;
(int)ch<
12345[Enter]
123453
【分析】第一次输入超长,字符串按长度取了"
1234"
,而'
5'
仍残留在缓冲区中,所以第二次输入字符没有从键盘读入,而是直接取了'
,所以打印的ASCII值是53('
的ASCII值)。
1234[Enter]a[Enter]
123497
【分析】第二次输入有效,说明该函数把第一次输入后的Enter丢弃了!
3.cin.getline()
4.cin.getline()与cin.get(array_name,Arsize)的读取方式差不多,以Enter结束,可以接受空格字符。
按照长度(Arsize)读取字符,会丢弃最后的Enter字符。
但是这两个函数是有区别的:
cin.get(array_name,Arsize)当输入的字符串超长时,不会引起cin函数的错误,后面的cin操作会继续执行,只是直接从缓冲区中取数据。
但是cin.getline()当输入超长时,会引起cin函数的错误,后面的cin操作将不再执行。
(具体原因将在下一部分"
cin的错误处理"
中详细介绍)
5.程序8:
intmain()
ch,
cin.getline(a,
5);
测试输入:
12345[Enter]
1234
-52
【分析】与cin.get(array_name,
Arsize)的例程比较会发现,这里的ch并没有读取缓冲区中的5,而是返回了-52,这里其实cin>
ch语句没有执行,是因为cin出错了!
下一部分将详细介绍。
深入了解cin错误处理机制,深入了解cin.clear/cin.ignore/cin.good/cin.fail等函数
在前一节中我们有几个例子中提到了cin函数出错,以致不再执行读操作(程序8)。
而且我们经常会看到程序中会出现cin.clear(),cin.ignore(),cin.fail()等函数。
这些函数都是与cin的错误处理有关的。
这一节我们来分析一下cin的错误处理机制,并且学习几个重要的函数:
cin.fail(),cin.bad(),cin.good(),cin.clear(),cin.ignore()等。
程序执行时有一个标志变量来标志输入的异常状态,其中有三位标志位分别用来标志三种异常信息,他们分别是:
failbit,eofbit,badbit。
这三个标志位在标志变量中是这样分配的:
____________________________________
|2|1|0|
|failbit|eofbit|badbit|
|___________|__________|___________|
看一下这几个标志位的作用(引用msdn):
badbit,torecordalossofintegrityofthestreambuffer.
eofbit,torecordend-of-filewhileextractingfromastream.
failbit,torecordafailuretoextractavalidfieldfromastream.
Inaddition,ausefulvalueisgoodbit,wherenobitsareset.
接下来我么看几个iOS类的数据定义(引用msdn):
typedefT2iostate;
staticconstiostatebadbit,eofbit,failbit,goodbit;
这里ios类定义了这四个常量badbit,eofbit,failbit,goodbit,其实这四个标志常量就是取对应标志位的掩码,也即输入的四种异常情况!
以上四个常量对应的取值为:
ios:
:
badbit001输入(输出)流出现致命错误,不可挽回
eofbit010已经到达文件尾
failbit100输入(输出)流出现非致命错误,可挽回
goodbit000流状态完全正常,各异常标志位都为0
我们可以用输出语句来验证这几个常量的值:
cout<
ios:
failbit<
endl;
eofbit<
badbit<
goodbit<
输出的结果为:
4
2
1
【注意】它们不是failbit、badbit、eofbit、goodbit这四个标记位的存贮变量,而是四个标志四种异常状态的常量,其实他们就相当于取对应状态标志位的掩码。
如果标志变量为flag,则flag&
failbit就取得fail标志位。
搞清楚了标志位的原理后,我们来看几个关于异常标志的函数:
1、iostateios:
rdstate()
取标志变量的值,我们可以用该函数取得整个标志变量的值,再与前面定义的标志位常量相与就可以获得对应标志位的状态。
如:
voidTestFlags(ios&
x)//获得x流的三个标志位状态
{
cout<
(x.rdstate()&
badbit)<
failbit)<
eofbit)<
}
2、boolios:
fail()const;
1ortrueifrdstate&
failbitisnonzero,otherwise0orfalse.(引用msdn)
其中rdstate即通过rdstate()取得的标识变量的值,与failbit相与,即取得failbit标志位的值,如果结果非零则放回true,否则返回false。
即该函数返回failbit的状态,将标志位状态通过bool值返回。
3、boolios:
bad()const;
badbitisnonzero;
otherwise0.(引用msdn)
与fail()相似。
4、boolios:
good()const;
1ortrueifrdstate==goodbit(nostateflagsareset),otherwise,0orfalse.(引用msdn)
改函数取goodbit的情况,即三个标志位都0(即没有任何异常情况)时返回true,否则返回false。
5、voidios:
clear(iostate_State=goodbit);
该函数用来重置标识变量,_State是用来重置的值,默认为goodbit,即默认时将所有标志位清零。
用户也可以传进参数,如:
clear(failbit),这样就将标识变量置为failbit(即:
001)。
我们一般是用它的默认值,当cin出现异常,我们用该函数将所有标志位重置。
如果cin出现异常,没有重置标志的话没法执行下一次的cin操作。
如上一节的程序2的测试二为什么第二次输入操作没有执行?
程序8中cin>
ch为什么没有执行?
都是这个原因!
所以经常在程序中使用cin.clear(),为了重置错误标志!
6、另外还有一个函数voidios:
setstate(iostate_State);
这个函数也是用来设置标识变量的,但与clear()不同。
clear()是将所有标志清零,在置以参数新的标志。
而该函数不清零其他的标志,而只是将参数对应的标志位置位。
这个函数不是经常使用,这里不再赘述。
在搞清楚了这几个函数后,对cin输入操作的错误处理就有了比较深的了解了。
下面我们回过头来看看上一节程序8的测试,因为第一次用getline()读取字符串超长,所以导致出现异常,大家可以查看一下标志位来验证一下!
所以会导致后面的cin>
ch语句没有执行。
那我们利用前面学习的clear()函数来强制重置错误标志,看看会出现什么情况呢?
程序9:
intmain()
charch,str[20];
cin.getline(str,5);
cout<