文章

洛谷里getline函数的深渊巨坑

一次折磨的经历

洛谷里getline函数的深渊巨坑

今天刷到一道字符串的题,题倒不难,但是AC过程十分艰辛

上链接:P7184

我的代码先是过了题目的3个样例,但是一提交全红

然后手写了几个样例,也过了,那是怎么肥事呢 . . .

于是我就找题解对拍,结果非常amazing,拍了1000个数据都是对的

不会是题改了,题解没改吧?我又把题解提交了,题解又是AC的

cin和getline

折腾许久后,我发现题解使用的都是cin来读入,于是我只将getline换成了cin,不出意料AC了

简单概括一下cingetline的区别:

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 >> rcin.ignore()忽略掉输入流开头的\n就行,但是代码到了Linux,输入流变成了5\r\nSSPPR\r\n1\r\nSSPPR,读入5之后,需要消耗两个字符才到SSPPR,即cin.ignore(2),而本地调试时,也想不到要忽略2个字符

如果这么写就会出现:本地样例通不过,代码一提交,欸?过了

而且在不知情的情况下,谁会直接提交认为错误的代码啊. . .

结束了

所以能用cin就用cin吧,cin忽略掉所有空白就说明它的容错率必定更高

打不死我的,一直在打我(╥﹏╥)

本文由作者按照 CC BY 4.0 进行授权

热门标签