那些年我们一起踩过的坑——读取字符(串)篇

前言

写了这么久 C / C + + C/C++ C/C++,自以为对各种输入输出都了如指掌,直到再次做题才明白自己仍有很多地方不太了解。尤其是读取字符时经常“炸锅”,最近碰到不少控制台秒关,得不到正确的字符/字符串等现象。如今深知不能再深受其害,予攥此文以记之

输入缓冲区

所谓键盘输入缓冲区,就是我们在输入的时候,程序并不会根据我们每次输入读取相应的内容,而是先将我们输入的内容全部存储到一个缓冲队列中,包括空格回车。但是回车会作为每次输入结束的标志,输入回车后程序根据我们需要得到的数据类型,从前到后向缓冲区获取相应内容,如果获取成功则缓冲区的内容被提取,输入的多余内容仍然会被保留在缓冲队列中,用于下一次读取

当我们读取数字时,空格和回车并不会造成影响,但是当我们读取字符或者是字符串时,必须要注意输入的空格和回车!但是要注意C/C++不同的输入流的处理方式不同

scanf的坑

scanf读入字符

之前我一直这样记忆: s c a n f scanf scanf读入字符遇到回车就会结束。但是我没注意过我输入的回车也被保留在了输入缓冲区。那么问题来了,如果有多个字符输入且用回车分隔,那么后面的字符去缓冲区提取的时候,回车也就不服了,凭啥你" a b c d abcd abcd"和空格啥的都是字符,俺就不是,于是回车就被当做字符被 c h a r char char类型的变量获取。然后我们就一头雾水——怎么没有得到我们需要的字符呢。所以 s c a n f scanf scanf对于 c h a r char char类型的变量,可以从输入缓冲区得到任意字符包括空格回车。

解决办法

1.在每次读入回车时加上一个 g e t c h a r getchar getchar

char c1,c2;
scanf("%c",&c1);
getchar();
scanf("%c",&c2);

/*输入:
a
b
得到:
c1=a,c2=b
*/

2.使用 f f l u s h ( s t d i n ) fflush(stdin) fflush(stdin)清空输入缓存区所有字符

如下所示,我们第一次输入 a a a后,跟了一串空格和其他字符,当我们按回车后程序开始读取 c 1 c1 c1,然后赋值为’ a a a'接下来的一串字符包括回车仍然存在于输入缓冲区,此时使用该函数,那么接下来的一串字符包括回车都被清除,接着我们再输入 b b b和回车, c 2 c2 c2被赋值为 b b b,回车仍存在于输入缓冲区。

char c1,c2;
scanf("%c",&c1);
fflush(stdin);
scanf("%c",&c2);

/*
输入:
a空格空格dfss空格
b
得到:
c1=a,c2=b
*/

scanf读入字符串

使用 s c a n f ( scanf( scanf(" % s \%s %s" ) ) )读入字符串时,空格和回车都被当做字符串分割符,也就是遇到空格空格或将该空格以前的字符串赋值给相应字符串。本以为字符缓冲区的回车也会被获取,但实际上并不会被获取。

gets()读入字符串

g e t s ( ) gets() gets()只把回车当做结束标志,因此类似于 g e t l i n e ( ) getline() getline(),它能接受字符缓冲区的回车,因此也要使用 g e t c h a r ( ) getchar() getchar()或者 f f l u s h ( ) fflush() fflush()消去回车。

char a[30];
int x;
scanf("%d",&x);
getchar();
gets(a);
cin的坑

cin>>

1. c i n > > cin>> cin>>后面可以跟任何基本数据类型(包括 c h a r ∗ char* char, s t r i n g string string等),而且这里有很严格的输入标志,即遇到空格回车都会作为分隔符, c i n cin cin也使用输入缓冲区,但是即便是输入字符(串),在字符缓冲区获取字符时,也会跳过空格和回车,仅以文件结束符作为结束标志。

2.正因为 c i n cin cin的以上特性,因此多样例输入完全可以按照以下方式进行:

T t;

while(cin>>t){
	...
}

getline

g e t l i n e getline getline c i n cin cin输入流下读取单行字符串的一个函数,用法为 g e t l i n e ( c i n , s t r i n g   s ) getline(cin,string ~s) getline(cin,string s)。值得注意的是虽然回车作为结束符,但是输入缓冲区的回车却会对字符串产生影响,就是如果之前的输入将回车放入了输入缓冲区,那么接下来用 g e t l i n e getline getline就会得到空串。以前我一直以为 s t r i n g string string没有结束标志符,但是当我去网上查阅资料,发现是这样的:

std::string:标准中未规定需要\0作为字符串结尾。编译器在实现时既可以在结尾加\0,也可以不加。但是,当通过c_str()来把std::string转换为const char *时,会发现最后一个字符是\0。因此C++11,string字符串都是以’\0’结尾

但是我们知道, s t r i n g string string是无法访问最后的结束符的,我猜测长度为 l e n len len s t r i n g string string有效访问内容是 [ 0 , l e n − 1 ] [0,len-1] [0,len1],结束符也许就在第 l e n len len位但是无法访问

因此上面的疑惑就可以解释清了:getline在读取字符串时,以回车作为字符串的结束标志符,因此当遇到回车时,将回车转换为结束标志符后读取结束。因此如果在读取前在输入缓冲区检测到回车,那么该字符串直接添加结束标志符导致为空串

解决办法

c i n . i g n o r e ( ) cin.ignore() cin.ignore()是专门用来消除结束输入缓冲区的回车的函数

string s1,s2;
cin>>s1;
cin.ignore();
getline(cin,s2);
cout<<s1<<s2<<endl;

/*
输入:
Ha
ppig
输出:
Happig
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值