整行读入的简单应用举例
为什么gets
会编译不通过?
简单地说,C++14 的标准规范已经删除了这个函数。
所以只要编译器是按照 C++14 的标准编译的,这个函数就是不存在的。
删除的原因是它函数设计上的安全缺陷。
C++的高版本会逐渐普及,很多 oj 都可能会有默认 14 及以上的编译标准。
大多数目前的比赛还是以 C++11 为标准的。
getline
最好是看手册,但如果你不是一个硬核的语法粉丝,可能看手册会比较吃力。下面我具一些例子,只针对算法竞赛实用的情况。
一般我们说到 getline,是指下面两个之一:
std::getline()
std::cin.getline()
std::getline()
只能读给std::string
类型(函数签名很长,这里不给出了,可以看手册)
{
string s;
getline(cin, s);
cout << s << endl;
}
但是我不推荐这样做,因为 string 的后续处理比较慢。
std::cin.getline()
的参数列表是:getline(char_type *__s, streamsize __n)
也就是说它可以读给字符串数组,第二个参数指定读入缓冲的大小。
考一个 C 语言基础题,
s[25]
这个数组,最多可以存几个字符?答:24 个,数组范围是 0-24,其中第 24 个位置是字符串结束符
'\0'
,0-23 的位置存储了 24 个有效字符。
{
char s[25];
cin.getline(s, 25);
cout << s << endl;
}
总而言之,如果要用getline
不可避免地要面对cin
。我的建议是不要把scanf
与cin
混用。
特别做法
如果你对cin
有偏见可以这样写:
{
char s[25];
scanf("%[^\n]",s);
getchar();
puts(s);
scanf("%[^\n]",s);
getchar();
puts(s);
}
matches a non-empty sequence of character from set of characters.
If the first character of the set is
^
, then all characters not in the set are matched.
简单地说,[^\n]
这里的意思是,把缓冲区内除了换行符以外的所有符号都读下来。这个设置还有很多有趣的特性,可以自行研究。
注意缓冲中的换行符是没有被读入的,所以,和gets
用法类似,你要取掉换行符。
至于到底谁的效率高,这个的测过猜知道。(我没测)
某个朋友的经验是,getline 可能更快。
花边操作
getline
的重载函数有第三个参数,是分隔符delimeter
,你可以理解为,它可以指定换行符之外的分隔符。
这样就可以做一些比较不可思议的事情:
{
string s;
while (getline(cin, s, '$')) {
cout << s << " ";
}
}
/*
input:ababac$shiahia$shaishi
output:ababac shiahia shaishi
*/
这里的每一个s
都是按照'$'
分割的结果。
由此我可以写出下面一个简单的split
函数。(偷懒的我没有把分隔符作为参数放进去)
vector<string> split(const string &raw) {
vector<string> vec;
stringstream ss(raw);
static string si;
while (getline(ss, si, '$')) {
vec.emplace_back(si);
}
return vec;
}
结果会是下面这样的:
s := ababac$shiahia$shaishi
[split(s)] := {"ababac", "shiahia", "shaishi"}
s := aba$shia$shais
[split(s)] := {"aba", "shia", "shais"}