【C标准输入输出】第三篇:C语言标准输出输出函数printf、scanf、缓冲区

wuchangjian2021-11-03 22:52:15编程学习

冲鸭

文章目录

  • C标准输入输出
  • 字符I/O函数
    • 字符输出函数
      • putchar
      • puts
    • 字符输入函数
      • getchar
      • gets
  • 格式化输出输出函数
    • 格式化输出函数
      • printf
        • printf转换说明
        • specifier
        • width
        • flags
        • .precision
        • length
      • sprintf
    • 格式化输入函数
      • scanf
        • scanf类型说明
      • scanf进阶用法
        • 指定读取长度
        • 匹配特定字符
      • scanf行为
        • scanf连续输入
        • scanf匹配失败
        • scanf不能忽略空白符
  • 缓冲区
    • 缓冲区的目的
    • 缓冲区的好处
    • 缓冲区类型
      • 全缓冲
      • 行缓冲
      • 不带缓冲
    • 缓冲区的特征
    • 缓冲区刷新
    • 清空缓冲区
      • 清空输出缓冲区
        • fflush(stdout)
      • 清空输入缓冲区
        • getchar
        • scanf
  • 总结

C标准输入输出

输入输出是指数据在用户与程序之间交互的过程,输出一般是指将数据(数字、字符)显示在输出设备上(屏幕),输入是指从输入设备上获取用户输入的数据

在C标准库中提供了输入输出函数,简称为I/O函数,这些函数可以在标准输入输出设备上对数据进行读写,常用的I/O函数可以分为格式化输入输出函数、字符输入输出函数

字符I/O函数

字符I/O函数是对字符类型数据在标准输入输出设备上进行读写,可以分为字符输入函数和字符输出函数

字符输出函数

putchar

函数原型:int putchar ( int character );

功能:将单个字符写入到标准输出

参数:单个字符

返回值:一旦成功,所写的字符就会返回。如果发生写错误,则返回EOF并设置错误指示符(ferror)

putchar

puts

函数原型:int puts ( const char * str );

功能:只能用于输出字符串,并且在输出结束后自动换行;将str指向的C字符串写入标准输出(stdout),并添加一个换行符(’\n’)。函数从指定的地址(str)开始复制,直到它到达结束的空字符(’\0’)

参数:要打印的字符串

返回值:如果成功,则返回一个非负值。当出现错误时,函数返回EOF并设置错误指示符(ferror)

puts

字符输入函数

getchar

函数原型:int getchar ( void );

功能:从stdin获取字符返回标准输入(stdin)的下一个字符

参数:none

返回值:如果成功,则返回读的字符(提升为int值)。返回类型为int,以适应特殊值EOF,该值表示失败:如果标准输入在文件末尾,则函数返回EOF,并设置stdin的EOF指示符(feof)。如果发生其他读取错误,该函数也返回EOF,但设置其错误指示符(ferror)

getchar

gets

函数原型:char * gets ( char * str );

功能:从标准输入(stdin)中读取字符,并将它们作为C字符串存储到str中,直到到达换行符或文件结束符。如果找到换行符,则不会将其复制到str中。在复制到str的字符之后会自动附加一个终止空字符

参数:指向一个内存块(char数组)的指针,在该内存块中读取的字符串将作为C字符串复制

返回值:如果成功,函数将返回str。如果在试图读取字符时遇到文件结束符,则设置eof指示符(feof)。如果在读取任何字符之前发生这种情况,则返回的指针为空指针(并且str的内容保持不变)。如果发生读错误,则设置错误指示器(ferror)并返回一个空指针(但str所指向的内容可能已经更改)

格式化输出输出函数

格式化I/O函数可以在标准输入输出设备上以各种不同的格式读写数据

格式化输出函数

printf

函数原型:int printf ( const char * format, ... );

功能:将格式化的数据打印到标准输出将格式指向的C字符串写入标准输出(stdout)。如果format包含格式说明符(以%开头的子序列),则format后面的附加参数将被格式化并插入到结果字符串中,替换它们各自的说明符

参数:参数为可变长列表,包含要写入标准输出的文本的C字符串。它可以选择性地包含嵌入的格式说明符,也称为转换说明,他们指定了如何把数据转换成可显示的形式,这些格式说明符被随后的附加参数中指定的值替换,并按照请求进行格式化

返回值:如果成功,则返回所写的字符总数。如果发生写错误,则设置错误指示符(ferror)并返回一个负数,如果在写入宽字符时发生多字节字符编码错误,则将errno设置为EILSEQ并返回一个负数

printf转换说明

printf转换说明遵循这个原型:

%[flags][width][.precision][length]specifier
flags:标志
width:宽度
.precision:精度
length:长度
specifier:说明符
末尾的说明符字符是最重要的部分,因为它定义了类型和对应参数的解释
[flags][width][.precision][length]:子说明符,也叫修饰符,可选项

specifier

specifier:末尾的说明符字符是最重要的部分,因为它定义了类型和对应参数的解释

转换说明符输出
%a浮点数、十六进制和p记数法
%A浮点数、十六进制和p记数法
%c单个字符
%d有符号的十进制整数
%e浮点数、e记数法
%E浮点数、e记数法
%f浮点数、十进制记数法
%g根据值的不同,自动选择%f或%e,%e格式用于指数小于-4或者大于或等于精度
%G根据值的不同,自动选择%f或%e,%e格式用于指数小于-4或者大于或等于精度
%i有符号十进制整数
%o无符号八进制整数
%p指针
%s字符串
%u无符号十进制整数
%x无符号十六进制,使用十六进制of
%X无符号十六进制,使用十六进制oF
%%打印一个百分号
转换说明格式符

转换说明结果

width

width描述
number要打印的最小字符数。如果要打印的值比这个数字短,结果将用空格填充。即使结果更大,该值也不会被截断
*宽度不是在格式字符串中指定的,而是作为必须格式化的参数前面的一个附加整数值参数
转换子说明符width

flags

-在给定的字段宽度内左对齐;右对齐是默认值
+对正数强制在结果前面加上一个正号或负号(+或-)。默认情况下,只有负数前面有-号
空格space如果不写符号,则在值之前插入一个空格
#与o, x或x指示符一起使用,对于不同于零的值,值前面分别有0,0x或0x。与a, a, e, e, f, f, g或g一起使用,它强制输出包含一个小数点,即使后面没有更多的数字。默认情况下,如果后面没有数字,则不写小数点
0当指定填充时,用0(0)左填充数字,而不是空格(参见宽度子说明符)
转换字说明符flag

.precision

.precision描述
.number对于整数说明符(d, i, o, u, x, x): precision指定要写入的最小数字数。如果要写入的值比这个数字短,结果将用前导零填充。即使结果较长,该值也不会被截断。精度为0意味着不为值0写入字符。对于a, a, e, e, f和f说明符:这是小数点后要打印的位数(默认是6)。对于g和g说明符:这是要打印的最大有效位数。对于s:这是最大的字符数
.*精度不是在格式字符串中指定的,而是作为必须格式化的参数前面的一个附加整数值参数
转换字说明符精度

length

长度子说明符修改数据类型的长度。这是一个图表,显示了用于解释有长度说明符和没有长度说明符的相应参数的类型(如果使用不同的类型,如果允许,将执行适当的类型提升或转换)

printf长度

sprintf

函数原型:int sprintf ( char * str, const char * format, ... );

功能:将格式化的数据写入字符串如果在printf上使用format,将打印相同的文本,但内容不会被打印,而是以C字符串的形式存储在str指向的缓冲区中。缓冲区的大小应该足够大,以包含整个结果字符串(参见snprintf获得更安全的版本)。在内容之后会自动附加一个终止空字符。在format形参之后,函数期望至少与format所需的参数一样多的附加参数

参数

str:指向存储C-string结果的缓冲区的指针,缓冲区应该足够大,以容纳产生的字符串
format:格式字符串,该格式字符串遵循与printf格式相同的规范
...:根据格式字符串的不同,函数可能需要一系列附加参数
每个参数都包含一个用于替换格式字符串中的格式说明符的值(或者一个指向存储位置的指针,对于n)
这些参数的数量至少应该与格式说明符中指定的值的数量一样多。其他参数被函数忽略

返回值:如果成功,则返回所写的字符总数。此计数不包括自动附加在字符串末尾的其他空字符,如果失败,则返回一个负数

sprintf

格式化输入函数

scanf

函数原型:int scanf ( const char * format, ... );

功能:从stdin读取数据,并根据参数格式将数据存储到附加参数所指向的位置。附加变量参数应该指向已经分配的对象,即根据变量将读取到的数据写入到内存,该对象的类型由格式字符串中相应的格式说明符指定

参数:可变长度参数列表,包含一个字符序列的C字符串,该序列控制如何处理从流中提取的字符

返回值:如果成功,函数将返回成功填充参数列表的项数。该计数可以匹配预期的项数,或者由于匹配失败、读取错误或文件结束的范围而小于(甚至为零)。如果发生读取错误或在读取时到达文件结束,则设置正确的指示符(feof或ferror)。并且,如果任何一种情况发生在任何数据可以成功读取之前,则返回EOF。如果在解释宽字符时发生编码错误,该函数将errno设置为EILSEQ

scanf类型说明

scanf转换说明遵循这个原型:

%[*][width][length]specifier
scanf的类型转换符与printf的类型转换符整体含义一致

scanf进阶用法

指定读取长度

在转换说明符中间加入一个数字,用来表示读取数据的最大长度

scanf读取指定长度

匹配特定字符

%s:控制符会匹配除空白符以外的所有字符

%【xxxx】:匹配需要读取的字符集合

%【a-z】:支持使用连字符-来表示一个范围内的字符

%【a-zA-Z】:表示读取大写字母和小写字母,也即所有英文字母

%【^ 0-9】:支持在不匹配字符前面加^,表示匹配除十进制数字以外的所有字符,遇到十进制数字就停止读取

%* d:允许把读取到的数据直接丢弃,不忘变量里存放,在% 后面加上*,表示读取一个整数并丢弃

scanf匹配特定字符

scanf行为

scanf是从标准输入设备(键盘)读取数据,带有行缓冲区

当调用scanf输入函数时,程序会先检查输入缓冲区是否有数据

1、输入缓冲区没有数据,就等待用户从标准输入设备输入数据,输入的数据被保存到缓冲区,按下回车键产生换行符’\n’,输入结束,scanf再从缓冲区中读取数据,赋值给变量

2、输入缓冲区有数据,具体情况是否符合控制字符串的规则:

  • 如果能匹配整个控制字符串,直接从缓冲区中读取,不需要等待用户输入

  • 缓冲区剩余的所有数据只能匹配前半部分控制字符串,等待用户输入剩下的数据

  • 如果不符合控制字符串的规则,则scanf会尝试忽略一些空白符,例如空格、制表符、换行符

    • 如果尝试成功则会重复上面的匹配过程
    • 尝试失败,就会读取失败
scanf函数行为

scanf连续输入

scanf连续输入

scanf匹配失败

scanf匹配失败

scanf不能忽略空白符

scanf空白符1 scanf空白符2 scanf空白符3

缓冲区

缓冲区(Buffer)又称缓存(Cache),是内存空间的一部分,即计算机在内存中预留了一定的存储空间,用来暂时保存输入与输出的数据,这个预留空间就叫缓冲区

缓冲区的目的

缓冲区是为了让低速的输入输出设备和高速的用户程序能够协调工作,并降低输入输出的读写次数

缓冲区的好处

  1. 可以将数据放入到缓冲区,然后程序继续往下执行,所有数据准备好之后一次性写到磁盘,减少了程序的等待次数,运行更加流畅
  2. 可以减少硬件设备的读写次数,程序不能直接读写硬件,是通过操作系统内核去调用驱动程序,让驱动程序才能真正的操作硬件;从用户程序到硬件设备要经过好几层的转换,每一层转换都有时间和空间的开销,若程序需要频繁的输入输出操作,会影响程序性能

缓冲区类型

不同的标准,缓冲区有不同的分类

根据缓冲区对应的是输入设备还是输出设备,可以分为输入缓冲区和输出缓冲区

根据数据刷新时机,可以分为全缓冲、行缓冲、不带缓冲

全缓冲

即当缓冲区被填满之后才进行真正的输入输出操作,缓冲区的大小都是由限制的,比如1KB,4MB

数据量达到最大值时就清空缓冲区

全缓冲的典型代表为对硬盘文件的读写

行缓冲

当在输入输出的过程中遇到换行符时从,才执行真正的输入输出操作

行缓冲的典型代表为标准输入设备(键盘)和标准输出设备(显示器)

printf、scanf输入输出函数都是自带行缓冲区

不带缓冲

不带缓冲区,数据就没有地方缓存,必须立马进行输入输出

错误信息输出函数perror也没有缓冲区,错误信息必须刻不容缓、立即、马上显示出来

缓冲区的特征

C语言标准规定输入输出缓冲区的特征

当且仅当输入输出不涉及交互设备时,它们才是全缓冲的

错误显示设备不能带有缓冲区(没有专门的错误显示设备,所有信息都显示到一个屏幕上)

缓冲区刷新

刷新缓冲区就是将缓冲区中的内容送到到目的地,缓冲区刷新的规则:

  • 不管是行缓冲还是全缓冲,缓冲区满了就会自动刷新
  • 行缓冲遇到换行符\n时会刷新缓冲区
  • 关闭文件时也会刷新缓冲区
  • 程序关闭时一般也会刷新缓冲区,这个是由标准库来保障的
  • 使用特定的函数也可以手动刷新缓冲区(getchar、scanf、fflush、rewind)
  • getchar、scanf在任何平台、任何编辑器都具有刷新缓冲区

清空缓冲区

缓冲区加快了程序的运行速度,减少了硬件的读写次数,使得计算机运行变得更加流畅,但避免缓冲区中残留数据引发的奇怪行为,应当在输入输出之前刷新缓冲区、

  • 输出操作:清空缓冲区使得缓冲区中的所有数据显示在屏幕上
  • 输入操作:清空缓冲区就是清理缓冲区数据

清空输出缓冲区

fflush(stdout)

fflush()是一个专门用来清空缓冲区的函数,stdout是standard output的缩写,表示标准输出设备,即显示器,清空标准输出缓冲区

fflush

清空输入缓冲区

getchar

getchar是带缓冲区的,每次从缓冲区中读取一个字符,包括空格、制表符、换行符等空白符,让getchar()不停的读取缓存区,直到读完缓冲区中所有字符

getchar清空缓冲区

scanf

scanf可以使用类似正则表达式的通配符,可以读取所有字符,包括空格、换行符、制表符等空白符,还允许把读取到的数据直接丢弃,不用复制给变量

scanf("%*[^\n]"); scanf("%*c");

总结

C提供各了标准输入输出函数,根据C标准库中函数原型对这些函数进行了解析,并结合缓存区理解了输入输出函数在标准输入输出设备上对数据进行的读写操作

赶紧学习起来吧!我是一个正在努力找回自我的人,希望能和一起学习的人成长,有错误的地方请各位大佬帮忙指正,如果觉得有帮助就点个赞当作对我的一个小肯定❤,peace&love

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。