测试环境:g++ version 13.1.6 (clang-1316.0.21.2.3)
读取多个字符
cin、scanf(读取连续的几个字符):
规则:
输入缓冲区有数据:从输入缓冲区读取,从非空字符开始,遇到空格结束(回车、空格、tab)。末尾回车会被留在输入缓冲区,并且不做处理。
输入缓冲区没有数据:获取键盘输入,当按下回车的时候,输入的数据连同刚按下的回车符被送入输入缓冲区。然后从输入缓冲区区读取数据,规则和上面标黄部分一样。
测试代码
#include <stdio.h>
int main() {
char str1[12];
char str2[13];
scanf("%s", str1);
scanf("%s", str2); // 如果缓冲区有数据,那么不会从键盘获取
printf("str1:%s,str2:%s", str1, str2); // 最后有个百分号是操作系统的提示符,如果加了换行就没有了
return 0;
}
输入、输出
➜ code ./a
str1 str2 # 空格 str1 空格 str2 回车
str1:str1,str2:str2% # 这里的输出可以看到scanf是跳过了空格,也就是从非空格字符开始空格字符结束
➜ code
结论:
1、scanf从非空格字符开始读取,空格字符结束(空格、TAB、回车)
2、当缓冲区没有数据的时候,需要先从键盘输入,然后放入缓冲区再读取。
3、当缓冲区有数据的时候不会从键盘获取数据。我们可以从上面输入看到第二个sacnf并没有从键盘获取数据
4、sacnf会把末尾回车留在缓冲区,给以后的输入埋雷
图表描述
gets、geline(读行):
规则
gets:
- 原型:char* gets( char* str );
- (deprecated in C++11)
- (removed in C++14)
getline:
- 头文件:string
- getline(cin, str)
输入缓冲区有数据:从输入缓冲区读取,这里的读取会连同空格一起读取,遇到末尾回车结束,回车也会读取并丢弃,所以换行符不会留在输入缓冲区中。
输入缓冲区没有数据:获取键盘输入,当按下回车的时候,输入的数据连同刚按下的回车符被送入输入缓冲区。然后从输入缓冲区区读取数据,规则和上面标黄部分一样。
代码测试
#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;
int main() {
char ch1[12];
char ch2[12];
string str1;
gets(ch1);
getline(cin, str1); // getline用来测试gets会不会留尾行回车
gets(ch2); // gets用来测试getline会不会留回车
cout << "gets1:"<< ch1 << endl;
cout << "getline:"<< str1 << endl;
cout << "gets2:"<< ch2 << endl;
return 0;
}
输入、输出:
➜ code ./a
warning: this program uses gets(), which is unsafe.
a1 1a # gets输入:空格a1空格1a回车
a2 2a。# getline输入:空格a2空格2a回车
a3 3a # gets输入:空格a3空格3a回车
gets1: a1 1a
getline: a2 2a
gets2: a3 3a
➜ code
结论:
1、gets、get line都可以读空格
2、缓冲区的尾行回车都被读取丢弃
图标描述
单字符读取
getchar
输入缓冲区有数据:从输入缓冲区逐字符读取,这里的读取会连同空格一起读取,遇到末尾回车结束,回车也会读取,输出’\n’ ASCII值为10
输入缓冲区没有数据:获取键盘输入,当按下回车的时候,输入的数据连同刚按下的回车符被送入输入缓冲区。然后从输入缓冲区区读取数据,规则和上面标黄部分一样。
_getch(getch)输入取消回显
_getch函数功能:不用输入回车就可以获取用户输入,并且不在终端中显示,可以保护用户隐私。
程序:
#include<iostream>
#include<string>
#include<windows.h>
#include<conio.h> // _getch()
using namespace std;
int main() {
char str;
char str1[20];
int i = 0;
while (1) {
str = _getch(); // C++标准推荐_getch命名
if (str == '\r') {
cout << endl;
str1[i] = 0; // 不加结束符:烫烫烫烫烫烫烫烫烫烫。栈区不初始化默认是0xcd。而0xcdcd对应汉字烫
break;
}
cout << "*";
str1[i] = str;
i++;
}
cout << str1 << endl;
system("pause");
return 0;
}
结果:
********
avsdw123
请按任意键继续. . .
注意点:
1、_getch需要包含头文件conio.h
2、用户按下任意键而不需要回车就可以接受到用户的输入
3、输入回车返回 ‘\r’
cin、scanf、gets、getline读取EOF时返回值
EOF手动触发方法:windows:ctrl+Z ,MAC:ctrl+D
cin、gets、getline遇到EOF返回0.
scanf遇到EOF返回-1
关于C++11标准补充(scanf_s和gets_s)
C++11中不推荐使用scanf和gets,标准认为不安全。推荐使用scanf_s和gets_s,当读取字符或者字符串的时候,需要带第三个参数确定存储变量的大小。scanf_s(“%s”, &str, sizeof(str)) gets_s(str, sizeof(str)).
程序:
#include<iostream>
#include<string>
#include<windows.h>
using namespace std;
int main() {
char str[10];
scanf_s("%s", str, (unsigned int)sizeof(str));
cout << str << endl;
getchar(); // 用来忽略缓冲区的回车
gets_s(str, sizeof(str));
cout << str << endl;
system("pause");
return 0;
}
结果:
abcd
abcd
12af
12af
请按任意键继续. . .
注意:scanf_s不会丢弃缓冲区的回车