洛谷里getline函数的深渊巨坑
一次折磨的经历
今天刷到一道字符串的题,题倒不难,但是AC过程十分艰辛
上链接:P7184
我的代码先是过了题目的3个样例,但是一提交全红
然后手写了几个样例,也过了,那是怎么肥事呢 . . .
于是我就找题解对拍,结果非常amazing,拍了1000个数据都是对的
不会是题改了,题解没改吧?我又把题解提交了,题解又是AC的
cin和getline
折腾许久后,我发现题解使用的都是cin
来读入,于是我只将getline
换成了cin
,不出意料AC了
简单概括一下cin
和getline
的区别:
cin
: 跳过前导空白字符(空格、Tab、换行符),读到下一个空白符前,结束不消耗
getline
:读到下一个换行符前,结束消耗换行符
两者连用时要特别注意:第一个cin
可能残留换行符,第二个getline
什么都没读到
所以需要在第一个cin
用完之后再调用cin.ignore()
,消耗掉输入流中残留的换行符
1
2
3
4
5
int r, n;
cin >> r;
cin.ignore();
string sven;
getline(cin, sven);
以为这就够了吗,可惜我就是这么写的
真相大白
于是我就硬要用getline
来过,经过一番痛苦搜索之后
找到了这样一个文档:Windows 环境下造数据注意事项
这里就揭露了调试和评测环境的不同,自己调试在Windows,评测在Linux,初见端倪
文档总结来说就是:测试数据是人在Win系统写代码生成上传的,而上传的是二进制文件,所以到了评测环境,换行符还是Win风格的\r\n
,而Linux的换行符只认\n
,所以上传前需要用工具统一将\r\n
转换为\n
,至于为什么Win系统可以识别\r\n
,因为这是一个历史遗留问题,为了解决,Win的运行库会在底层将\r\n
转为\n
,而Linux都没这个问题也就不用转了,这道题的样例,正是保留了Win风格换行符的评测样例
不过,这个和getline函数有什么关联?
溯源
在这道题的输入顺序下,使用getline就必定要先调用cin.ignore()
,就拿第一个题目用例来说:
1
2
3
4
5
SSPPR
1
SSPPR
它在win中的流中\r\n
已经被转为\n
,所以自然cin >> r
后cin.ignore()
忽略掉输入流开头的\n
就行,但是代码到了Linux,输入流变成了5\r\nSSPPR\r\n1\r\nSSPPR
,读入5之后,需要消耗两个字符才到SSPPR
,即cin.ignore(2)
,而本地调试时,也想不到要忽略2个字符
如果这么写就会出现:本地样例通不过,代码一提交,欸?过了
而且在不知情的情况下,谁会直接提交认为错误的代码啊. . .
结束了
所以能用cin就用cin吧,cin忽略掉所有空白就说明它的容错率必定更高
打不死我的,一直在打我(╥﹏╥)