当字符遇上 scanf() 要当心
看一下程序
char ch1,ch2;
printf("请输入ch1,ch2的值:");
scanf("%c %c",&ch1,&ch2);
printf("ch1 = %c, ch2 = %c\n",ch1,ch2);
printf("请再次输入ch1的值:");
scanf("%c",&ch1);
printf("请再次输入ch2的值:");
scanf("%c",&ch2);
printf("ch1 = %c, ch2 = %c\n",ch1,ch2);
运行结果如下:
第二次输出为什么会出现异常情况呢 ?
这里有两个问题
- 为什么出现了
请再次输入ch1的值:请再次输入ch2的值:
的情况,按照原本的预测请应该是先出现请再次输入ch1的值:
,键盘输入了一个字符之后再出现请再次输入ch2的值:
,键盘再输入一个字符 - 为什么第二次输入ch1,的值后,直接就输出了ch1 和ch2 ,而且 ch1 = '\n', ch2 = 'C'?
第一个问题
首先需要知道CPU 的工作原理
由于输入设备和输出设备对于数据的读写速度比较慢,CPU为了降低输入输出次数,提高运行效率,避免长时间的等待,所以内核就在内存中提供了一块空间作为缓冲区,( 缓冲区也可以称为缓存(Cache),是属于内存空间的一部分。)
每当使用读操作函数,试图将数据读取出来时,数据都会流过标准*输入缓冲区*,然后再在适当的时刻冲洗(或称刷新,flush)到内核缓冲区,最后才真正得到数据。
所以CPU 并不是没每时每刻都在读取数据,而是在满足刷新条件时才会从出入缓冲区读取数据。刷新条件按形式分为三种:全缓冲、行缓冲、无缓冲。
全缓冲:指的是当缓冲区被填满就立即把数据冲刷到文件、或者在关闭文件、读取文件内容以及修改缓冲区类型时也会立即把数据冲刷到文件,一般读写文件的时候会采用
无缓冲:指的是没有缓冲区,直接输出,一般linux系统的标准出错stderr就是采用无缓冲,这样可以把错误信息直接输出。
行缓冲:指的是当缓冲区被填满(一般缓冲区为4KB,就是4096字节)或者缓冲区中遇到换行符’\n’时,或者在关闭文件、读取文件内容以及修改缓冲区类型时也会立即把数据冲刷到文件中,一般操作IO设备时会采用,比如printf函数就是采用行缓冲。
知道了CPU 工作原理之后,我们就知道了printf() 函数的刷新条件有四个:
- 程序结束;
- 遇到换行 ‘\n’;
- 缓冲区满;
- 利用函数fflush() 手动刷新.
这也就解释了为什么出现 请再次输入ch1的值:请再次输入ch2的值:
的情况,是因为没有遇到刷新条件,所以在写程序时,非必要情况都需要加上换行‘\n’。
第二个问题
在解释CPU 工作原理是说过 Linux 系统读取数据,是先从键盘进入到输入缓冲区,再进入到内核缓冲区,最后读取到数据。所以在第一次输入ch1 ,ch2 的值为A B<手动输入'\n'
,缓冲区应该是字符串
"A B\n", CPU 先读取“A B”,光标位置在字符B 的后面,当再次从缓冲区读取字符型数据时读出来的是字符‘\n’ ,ch1 = '\n', ch2 读取的是后面输入的字母C 。
那么我们如何解决这个问题呢?
在读取字符之前先要清空缓冲区,使用函数getchar() ,让光标后移到正确的位置,如下:
char ch1,ch2;
printf("请输入ch1,ch2的值:");
scanf("%c %c",&ch1,&ch2);
printf("ch1 = %c, ch2 = %c\n",ch1,ch2);
getchar(); //读取换行符
printf("请再次输入ch1的值:");
scanf("%c",&ch1);
getchar(); //读取换行符
printf("请再次输入ch2的值:");
scanf("%c",&ch2);
printf("ch1 = %c, ch2 = %c\n",ch1,ch2);
标签:字符,ch1,scanf,缓冲区,ch2,printf,当心,输入
From: https://www.cnblogs.com/JinBool/p/18182725