导图社区 第03课 输入输出专题
输入输出专题知识整理,包括标准l/O的缓冲类型、行缓冲、学习一个函数要掌握三个要素、回值字符输入&输出函数、字符串输入&输出函数、格式输入&输出函数、如何处理输入函数留下的垃圾。
编辑于2022-04-05 00:08:00第03课 输入输出专题
C语言中,没有依存于硬件的输入/输出语句,程序的输入/输出功能是通过调用输入/输出库函数实现的。 头文件<stdio.h>定义了用于输入/输出的函数、类型和宏
标准I/O的缓冲类型
标准I/O根据不同的应用需求,提供了全缓冲、行缓冲、无缓冲三种缓冲方式
全缓冲:只有当划定的缓冲区被填满或者数据读取至末尾时,才开始执行 I\O 操作(操作系统提供的 read\write 操作)。 磁盘文件的读写一般采用这种方式。
行缓冲:当输入输出过程遇到换行符''\n"或者当分配缓冲区已满时,才开始执行 I\O 操作。 一般涉及终端的读写操作如 stdin 与 stdout 使用这种缓冲方式。
无缓冲:当有数据产生时,马上由相应的设备进行处理。 一般来说 stderr(standard error) 使用这种缓冲方式,使得有错误信息时马上能够得到响应。 需要注意的是,标准库不缓存并不意味着操作系统或者设备驱动不缓存。
行缓冲
标准输入缓冲区stdin使用行缓冲的方式存储输入。用户的输入数据首先被暂存在临时缓冲区中,当用户键入回车键或临时缓冲区满后,stdin 才进行 I/O 操作,将数据由临时缓冲区拷贝至 stdin 中。 C语言提供的输入输出函数如 scanf 、getchar 等则从上述缓冲区 stdin 中读取数据输入。
scanf和getchar等函数会在stdin中读取数据,若上述缓冲区中已存在数据,则直接读取其中的数据;若上述缓冲区为空,则上述函数会挂起,等待数据缓冲的完成( 用户输入回车键或数据缓冲区满后, stdin 会进行数据缓冲,之后上述函数才能继续执行)。
用户一次输入的数据可能会超过scanf、getchar等函数调用所需要的数据,那么所需数据被读取后,剩余的数据仍会存放在缓冲区中,之后的函数调用会直接读取 stdin 中已有的数据。只有当缓冲区为空后,scanf、getchar 等函数才会重新等待用户输入(实际应该是等待 stdin 的缓冲)。
Linux中清空缓冲区的方法:通过读完标准缓冲区中的剩余字符并丢弃掉来清空标准缓冲区,使用getchar()函数。 如果需要清除stdin可以通过如下循环实现: char ch; while((ch=getchar())!='\n'&&ch!=EOF); //EOF是End Of File的缩写,在C语言标准库中的定义是:#define EOF (-1)
学习一个函数要掌握三个要素:基本功能、参数、返回值
字符输入&输出函数
字符输入函数
字符输入函数:int getchar(void) 功能:读取标准输入stdin中的一个字符 返值:正常,返回读取的代码值;出错或结束键盘输入,返回-1(ctrl+d)
思考:getchar()的返回值为什么是int型? 因为ASCII码的范围是0~255个,char的范围是-128~127,范围不够;而unsigned char虽然范围是0~255,但是不能接收-1(-1有特殊作用),所以就用int型来接收getchar()的返回值。
getchar()是从标准输入stdin中读取数据,而 stdin 是采用行缓冲的方式记录用户输入,也就是只有当用户键入回车键或输入至缓冲区末尾时(回车字符也放在缓冲区中),才会开始 I/O 操作,亦即读取一个字符。 如果用户一次输入不止一个字符,读取过后缓冲区可能不为空; 当再次调用getchar()时,若缓冲区不为空,getchar()就会直接读取在缓冲区中的字符,而不是等待用户输入。 所以可以认为:getchar()等待的是行缓冲的完成,而不是每一次调用getchar()都需要等待用户输入的完成。在行缓冲完成后,只要缓冲区不为空,再次调用的getchar()就可以直接读取字符,而不需要等待用户输入。直到缓冲区中的字符读完之后,才等待用户按键输入。
getchar() 可以直接从缓冲区中读取字符,而不等待用户输入,但这种方式也有可能带来潜在的错误。 在每次调用 getchar()函数之后,手动对缓冲区进行清除操作。 见上述Linux中清空缓冲区的方法
字符输出函数
字符输出函数:putchar(c) 参数:c为字符常量、字符型变量或表达式 功能:把字符c输出到显示器上 返值:正常,为显示的代码值(ASCII码值) 注:putchar()函数本身是最后不自动加回车符的
字符串输入&输出函数
字符串输入函数
字符串输入函数:char *gets(char *str) 参数:参数类型为 char* 型,即 str 可以是一个字符指针变量名,也可以是一个字符数组名 功能:从标准输入缓冲区stdin中读取一个字符串存储到字符指针变量 str 所指向的内存空间中(或存储到字符数组里),并自动在末尾加 '\0'
用户输入的字符串的长度应小于字符数组维数
gets()是有缓冲区的,每次按下回车键,就代表当前输入结束了,gets() 开始从缓冲区中读取内容,这一点和 scanf() 是一样的(“一样”是指都是回车键结束输入,开始从缓冲区读取内容)。
gets()和scanf()的主要区别是
关于“空格”问题
scanf()读取字符串时以空格为分隔,遇到空格就认为当前字符串结束了,所以无法完整读取含有空格的字符串。
gets()认为空格也是字符串的一部分,只有遇到回车键时才认为字符串输入结束,所以,不管输入了多少个空格,只要不按下回车键,对 gets() 来说就是一个完整的字符串。
如果想用scanf()输入带空格的字符串的话,就得用for循环的形式循环输入%c来实现; 但是如果既不想写for循环,又想输入带有空格的字符串的话,就得用gets()函数来实现。
关于“换行符”问题
使用gets()时,系统会将最后“敲”的换行符从缓冲区中取出来,然后丢弃,所以缓冲区中不会遗留换行符。 这就意味着,如果前面使用过 gets(),而后面又要从键盘给字符变量赋值的话就不需要吸收回车来清空缓冲区了,因为缓冲区的回车已经被 gets() 取出来扔掉了。
但是如果前面使用的不是 gets() 而是 scanf(),那么通过键盘给后面的字符变量赋值前就必须先使用 getchar() 清空缓冲区。(详见关于如何处理输入函数留下的垃圾)
字符串输出函数
字符串输出函数:int puts(const char *s) 参数:s可以是字符指针变量名、字符数组名,或者直接是一个字符串常量 功能:将字符串输出到屏幕(输出完,自动换行) 输出时只有遇到 '\0' 也就是字符串结束标志符才会停止。
puts()和printf()相对比
如果 puts() 后面的参数是字符指针变量或字符数组,那么括号中除了字符指针变量名或字符数组名之外什么都不能写。 例如printf() 可以这样写:printf("输出结果是:%s\n", str); 而puts()就不能使用如下写法:puts(输出结果是:str);
因此,puts() 虽然简单、方便,但也仅限于输出字符串,功能还是没有 printf() 强大
格式输入&输出函数
格式输入函数
格式输入函数:scanf(“格式控制串”,地址表) 参数:由指示读取动作的格式控制串( format string )和相应的地址参数 arg1...argn 组成。 功能:scanf() 函数将从标准输入缓冲区stdin中读取,并将它们以格式控制串中指定的格式存储到地址表中指定的内存空间中。其中,地址表指向的内存空间的数据类型应该与格式控制串中指定的数据类型相一致。 注:地址表:变量的地址,常用取地址符号&
用户每次按下回车键,程序就会认为完成了一次输入操作,scanf() 开始读取用户输入的内容,并根据格式控制串从中提取有效数据,只要用户输入的内容和格式控制串相匹配,就能够正确提取。 本质上讲,用户输入的内容都是字符串,scanf() 完成的是从字符串中提取有效数据的过程。
scanf()对字符和字符串的读取
scanf()函数在以%d形式读取数据时,会跳过空格,换行,Tab这些空白字符,遇到形如a10这样不符合要求的数据时,会读取失败; scanf()函数在以a=%d形式读取数据时,不会跳过空格,换行,Tab这些空白字符,在遇到这些空白字符或其他不符合要求的数据时会读取失败。
格式输出函数
格式输出函数:printf(“格式控制串”,输出表) 功能:按指定格式向显示器输出数据 printf的格式有四种: (1)printf("字符串\n"); (2)printf("输出控制符",输出参数); (3)printf("输出控制符1 输出控制符2…", 输出参数1, 输出参数2, …); (4)printf("输出控制符 非输出控制符",输出参数); 注:输出控制符:%开头的;其余就是非输出控制符
如何处理输入函数留下的垃圾
运行程序,当输入一个整型常量5后按回车键,程序就停止运行,并输出x=5,ch=10  分析:因为%c将回车键读取进去,导致第二个scanf不需用户输入就读取到了数据