在读这篇文章之前,先来记住两点:
- 空字符’\0’,它在内存中占一个字符,但不会影响字符串的长度,就是说我们用strlen()和size()函数返回字符串或字符数组长度的时候是不算空字符的。
- 输入回车是所有的输入函数的输入结束标志,它不等于空字符,也不等于’\n’字符。'\n’字符在字符串中是占位的。
1. 引言
输入输出是我们接触最多,但也最容易忽略的知识点。相信很多人都有过在输入输出上总是不 ac 的经历,因为输出取决于输入对不对,下面我们就来简单概括一下输入的精髓。
我们就从一道题说起吧:
- 第一步,输入一个整数 m,并输出
- 第二步,输入一行带空格的字符串,并输出
- 第三步,输入多行带空格的字符串,并输出
- 第四步,输入一个字符 c,并输出
感兴趣的可以自己试一下,如果对输入不熟悉的话,一定会像笔者开始那样懵逼。
下面我们就来给出答案:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int m;
cin >> m; //遇到空白(包括回车、空格等)结束输入,并且会把非int字符留在缓存区(包括回车,空格等空白字符)
cout << m << endl;
//回收缓存区的第一个字符(任意字符),如果不回收,那么下面的getline()接收到字符串的就是这个换行符
cin.get();
//输入一行带空白字符的字符串,遇到回车结束输入
string str;
getline(cin, str);
cout << str << endl;
//输入多行带空白字符的字符串,如果当前行只输入回车结束输入
string str1;
vector<string> vec;
while (getline(cin, str1)) {
if (str1.size() != 0) { //当前行只输入回车
vec.push_back(str1);
}
else {
break;
}
}
for (int i = 0; i < vec.size(); i++) {
cout << vec[i] << endl;
}
//输入一个字符,能够正常输出,可以看到getline()之后缓存区没有任何字符了,这也印证了getline()不会把回车留在缓冲区
char c;
cin >> c;
cout << c << endl;
return 0;
}
2. 输入常用 API
2.1 cin
cin是 c++ 中最常用的输入语句,当遇到空白字符(空格或者回车键)即停止,并且会把空白字符留在缓冲区
,容易造成数据的输入错误。
2.2 cin.get()
接收缓冲区的第一个字符,通常用来接收由cin产生的空白字符
。
2.3 cin.get(char *str, int maxnum)
参数说明:
- str:接收输入的字符串
- maxnum:最大可接受的字符数量,它必须小于等于str.size(),否则报错
从 2.2 就能看出来cin.get可以接收空格。
但这个函数很危险,因为它在缓冲区中创建了str.size()个字节的空间,如果我们输入的字符数量不够str.size(),那剩下的那段空间依然不会释放,如果我们后面还有输入字符或者字符串,就会优先接收缓冲区中的那段剩余字符串,也就是空白字符串"\0\0\0…"。
所以,这个函数不推荐使用,尤其是需要连续输入多行带空格的字符串的时候。
给两个例子对比就很清晰了。
int main()
{
//输入两行带空格的字符串
char str1[1024];
cin.get(str1, 1024);
cout << str1 << endl;
char str2[1024];
cin.get(str2,1024);
cout << str2 << endl;
return 0;
}
说明:上述例子中,cin.get(str1, 1024)在缓冲区开辟了1024个字节的空间,str1只接受了输入那一行的字符串那么多个字符。剩下的1000多个空白字符就都给了str2了,所以str2相当于直接遇到回车结束输入了,接收不到任何字符(字符串的长度为零)。
int main()
{
//输入两行带空格的字符串
char str1[5];
cin.get(str1, 5);
cout << str1 << endl;
char str2[1024];
cin.get(str2,1024);
cout << str2 << endl;
return 0;
}
说明:上述例子中,str1接收了"abcd"四个字符和一个’\0’,然后剩下的一个e被str2接收了。
2.4 getline(cin,str)
getline()可以输入一行,能接收空格,头文件是<string>
,所以用string来接收。遇到回车结束输入。这个函数适合用来输入带空格字符串,尤其是对于要连续输入多行带空格的字符串的时候,这个函数是最最最最合适的。
int main()
{
string str;
getline(cin,str); //getline需包含<string>
cout << str << endl;
return 0;
}
输入连续多行字符串请看最开始那个例子就行。
2.5 cin.getline(char *str, int maxnum)
这个函数的功能其实跟getline()完全一样,区别就是getline()是string流,而cin.getline(char *str, int maxnum)是istream流。所以在使用的时候是可以替换getline()的。
它不像cin.get(char *str, int maxnum)那样在缓冲区开辟str.size()的数据,而是输入多少就开辟多少,不会对后面的字符串输入产生任何影响。
int main()
{
//输入两行带空格的字符串
char str1[1024];
cin.getline(str1, 1024);
cout << str1 << endl;
char str2[1024];
cin.get(str2,1024);
cout << strlen(str2) << endl;
return 0;
}
int main()
{
//输入多行带空白字符的字符串,如果当前行只输入回车结束输入
char str1[1024];
vector<string> vec;
while (cin.getline(str1, 1024)) {
if (strlen(str1) != 0) { //当前行只输入回车
vec.push_back(string(str1));
}
else {
break;
}
}
for (int i = 0; i < vec.size(); i++) {
cout << vec[i] << endl;
}
return 0;
}