浅谈C/C++字符串输入scanf、gets、cin、getline、getchar

测试环境: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会把末尾回车留在缓冲区,给以后的输入埋雷

图表描述

以scanf为例图表描述

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、缓冲区的尾行回车都被读取丢弃

图标描述

gets、getline数据流向

单字符读取

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不会丢弃缓冲区的回车

  • 4
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

划水猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值