字符串:输入与缓冲区问题

<输入小结>

  • 函数 回显 缓冲区 头文件
  • getchar() stdio.h
  • getche() conio.h
  • getch() conio.h
  • scanf() stdio.h
  • gets() stdio.h
  • scanf() 是通用的输入函数。它可以读取多种类型的数据。
  • gets() 是专用的字符串输入函数,与 scanf() 相比,gets() 的主要优势是可以读取含有空格的字符串。

<输入单个字符>

1.scanf()
示例:

char str;
scanf("%c",&str);

2.getchar()
示例:
char c=getchar();
printf("c:%c\n", c);

字符串:输入与缓冲区问题_第1张图片

3.getche()
示例:
char c=getche();
printf("c: %c\n", c);

字符串:输入与缓冲区问题_第2张图片
解释:输入@后,getche() 立即读取完毕,接着继续执行 printf() 将字符输出,所以没有按下回车键程序就运行结束了。
注意:getche() 位于 conio.h 头文件中。而这个头文件是 Windows 特有的,Linux 和 Mac OS 下没有包含该头文件。但可以系统定义一个函数实现getche()功能。

4.getch()

补充:所谓回显,就是在控制台上显示出用户输入的字符;没有回显,就不会显示用户输入的字符,就好像根本没有输入一样。
回显在大部分情况下是有必要的,它能够与用户及时交互,让用户清楚地看到自己输入的内容。但在某些特殊情况下,我们却不希望有回显,例如输入密码,有回显是非常危险的,容易被偷窥

示例
char c=getch();
printf("c:%c\n", c);

getch()示例
解释:输入@后,getch() 会立即读取完毕,接着继续执行 printf() 将字符输出。但是由于 getch() 没有回显,看不到输入的@字符,所以控制台上最终显示的内容为c: @。
注意:和 getche() 一样,getch() 也位于 conio.h 头文件中。这个头文件是 Windows 特有的,Linux 和 Mac OS 下没有包含该头文件。但可以系统定义一个函数实现getche()功能。

<输入一个字符串>

1.scanf()

scanf函数在给字符数组赋值时,当从键盘输入字符串后,系统会自动在最后添加结束标志‘\0’。
注意:如果输入的字符串中带空格,比如字符串“i like red”。就会出现一个问题。

示例
char str[20];  
printf("请输入字符串:");
scanf("%s", str);  
printf("输出结果:%s\n", str);

字符串:输入与缓冲区问题_第3张图片
解释:系统将空格作为输入字符串之间的分隔符。也就是说,只要一“敲”空格,系统就认为当前的字符串已经结束,所以只会将空格之前的字符串存储到定义好的字符数组中。
解决办法1:
以空格为分隔符,计算有多少个字符串,有多少个字符串就定义多少个字符数组。比如“i like red”有两个空格,表示有三个字符串,那么就定义三个字符数组。
解决方法2:
使用gets函数

2.gets()

功能:从键盘将带空格的字符序列(以回车键结束)全部输入指定的字符数组,并自动加字符串结束符‘\0’。该函数可以将带空格的字符串全部输入字符数组中。

char str[20];  
printf("请输入字符串:");
gets(str);
printf("输出结果:%s\n", str);

gets()示例

<缓冲区>

  • 一、什么是缓冲区
    缓冲区是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。
    缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。
  • 二、为什么要引入缓冲区
    缓冲区能使得低速的输入输出设备和高速的CPU能够协调工作 。
    缓冲区主要作用是在于减少实际的I/O操作次数,即将多次操作尽量合并成一次的成批操作。举个例子:我们使用打印机打印文档,由于打印机的打印速度相对较慢,我们先把文档输出到打印机相应的缓冲区,打印机再自行逐步打印,这时我们的CPU还可以处理别的事情。

    补充:在程序的执行过程,首先从硬盘执行程序,存放到内存,再给CPU运算与执行。由于硬盘的速度要比内存慢得多,而内存的速度又比CPU慢得多。因为CPU速度比其它硬件都要快,如果每次程序只传输一点数据,就需要传送很多次,这样会浪费很多时间。
    注意:缓冲区与缓存并不相同
  • 三、缓冲区的类型
    缓冲区 分为三种类型:全缓冲、行缓冲和不带缓冲。
    1.全缓冲
    在这种情况下,当填满标准I/O缓存后才进行实际I/O操作。全缓冲的典型代表是对磁盘文件的读写。
    2.行缓冲
    在这种情况下,当在输入和输出中遇到换行符时,执行真正的I/O操作。这时,我们输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的I/O操作。典型代表是键盘输入数据。
    3.不带缓冲
    也就是不进行缓冲,标准出错情况stderr(标准错误)是典型代表,这使得出错信息可以直接尽快地显示出来。
  • 四、缓冲区的刷新
    下列情况会引发缓冲区的刷新:
    (1).缓冲区满时;
    (2).执行fflush语句;
    (3).执行endl语句;(C++)
    (4).关闭文件。
    可见,缓冲区满或关闭文件时都会刷新缓冲区,进行真正的I/O操作。另外,我们可以使用fflush函数来刷新缓冲区(执行I/O操作并清空缓冲区)
  • 五.键盘操作演示行缓冲
    getchar()函数的拓展介绍
    函数原型:int getchar(void);(返回值为用户输入的ASCII码
    说明:getchar()函数的执行就是采用了行缓冲。当程序调用getchar()函数时,程序就等着用户按键,用户输入的字符被存放在键盘缓冲区中,直到用户按回车为止,回车字符也放在缓冲区中。当用户输入回车之后,getchar()函数才开始从键盘缓冲区中每次读入一个字符。也就是说,后续的getchar()函数调用不会等待用户按键,而直接读取缓冲区中的字符,直到缓冲区中的字符读完后,才重新等待用户按键。

<输入多个字符串>

示例:
char  a[20];
char  str[20];
printf("请输入文件名:");
scanf("%s",a);
printf("请输入关键字:");
//getchar();
//fflush(stdin);
 gets(str);
 printf("%s\n",str);

字符串:输入与缓冲区问题_第4张图片
可以看到没等第二次的关键字的输入程序就运行结束了,为什么呢?
解释:当我们输入字符串file后按回车的时候就会把file连同换行符送入缓冲区,然而scanf只会接收字符串file,并把这个字符串送入到以a为首地址的地址空间中,同时在字符串后面自动加上一个‘\0’,那么如今缓冲区内就只有一个换行符了。当执行到gets()函数的时候,因为缓冲区内非空,无法输入字符串。gets直接会读取缓冲区中的换行符复制到str为首地址的内存空间,同时在字符串后面自动加上一个‘\0’,所以输出的str的结果是一个换行。
解决法1:当我们取消程序中注释语句getchar()的时候,getchar()会接收缓冲区中的第一个字符,那么缓冲区便空了。当执行到gets()的时候,由于缓冲区为空,那么程序便会停在gets()位置处的等待输入。
解决法2:也可以使用fflush(stdin)来刷新缓冲区,同样可以起到消除换行符的效果。因为fflush(stdin)的作用是清除标准输入缓冲区中的内容。

fflush()

函数原型:int fflush(FILE *stream)
fflush(stdin)刷新标准输入缓冲区,把输入缓冲区里的东西丢弃[非标准]。stdin表示标准键盘输入
fflush(stdout)刷新标准输出缓冲区,把输出缓冲区里的东西打印到标准输出设备上

注意:某些编译器(如VC6)支持用 fflush(stdin) 来清空输入缓冲,但是并非所有编译器都要支持这个功能。在这些支持fflush(stdin)的编译器中,当输入多个字符串时,特别是一行代码输入一个字符串时,必须在每个输入前加上fflush(stdin)。

你可能感兴趣的:(C语言知识点归纳)