scanf函数详解(本质理解)

本文详细解析了C语言中的scanf函数,包括其工作原理、格式化字符串规则、输入缓冲区的行为、转换说明中的*和数字修饰符,以及如何处理空格、扫描集和输入结束标志。特别关注了scanf函数在处理空格和输入结束时的特性和优化技巧。
摘要由CSDN通过智能技术生成

结构:

scanf("<格式化字符串>",<地址表>)

功能:

把输入的字符串转化(解释)为整数、浮点数、字符或字符串。

规则:

输入缓冲区是行缓冲区,除非特意对缓冲区进行刷新(也就是按下回车键),否则你的程序不会读到任何东西,回车符会使行缓冲区进行刷新,即回车符是输入结束的标志。虽然说输入的结束标志是回车键,但是回车键并不一定代表输入结束,如果你输入的并没有满足scanf语句读取的格式化的内容,scanf会把回车键视作一个空格。

scanf()函数使用空白(换行符、制表符tab、空格)把输入分成多个字段。在依次把转换说明和字段匹配时跳过空白。(唯一例外:根据%c,scanf()会读取每个字符包括空格)

从scanf()角度看输入

%d:假设scanf()根据一个%d转换说明读取一个整数,每次读取一个字符,跳过所有空白字符,直至遇到第1个非空白字符才开始读取。因为要读取整数,如果找到一个数字字符或符号(+或-),它便保存该字符,并读取下一个字符。直到遇到一个非数字字符,它便认为读到了整数的末尾。然后scanf()把非数字字符放回输入。那么程序下一次读取输入时,首先读到的是上一次读取丢弃的非数字字符。如果第一个非空白字符为非数字字符或符号,scanf直接退出。

%s:scanf()会读取除空白外的所有字符。scanf()跳过空白开始读取第1个非空白字符,并保存非空白字符直到再次遇到空白。当scanf()把字符串放进指定数组时他会在字符序列的末尾加上 '\0',让数组中的内容成为一个字符串。注意:读取字符串存入字符数组时'\0'也存入数组,所以数组长度至少为字符串长度+1。

格式字符串中的普通字符

除空格外的普通字符必须与输入字符串严格匹配。格式字符串中的空白意味着跳过下一个输入项前面的所有空白(所有空白包含没有空格的情况)。

scanf()转换说明中的修饰符

1、 *  :抑制赋值。用*修饰符代替字段宽度,但要用参数表示字段宽度。

scanf中的用法:把*放在%和转换字符之间,会使scanf()跳过相应的输入项。

 如上图,scanf()会跳过两个整数,把第三个整数拷贝给n。

printf中的用法:让修饰符由后面的参数指定。例:printf("%*d",10,a)和printf("%10d",a)意义一样,printf("%*.*f",8,3,a)和printf("%8.3f",a)意义一样。

 2、数字:含义为最大字符宽度。输入达到最大字符宽度出处,或第1次遇到空白字符时停止。

如上图,每次读取宽度为1的整形,读取两次。

缓冲区

scanf() 是带有缓冲区的。遇到 scanf() 函数,程序会先检查缓冲区中是否已经有数据

1、如果没有,就等待用户输入。用户从键盘输入的每个字符都会暂时保存到缓冲区,直到按下回车键,输入结束,scanf() 再从缓冲区中读取数据,赋值给变量。

2、如果有数据,哪怕是一个字符,scanf() 也会直接读取,不会等待用户输入。

注意:scanf() 匹配到想要的数据后,会将匹配到的数据从缓冲区中删除,而没有匹配到的数据仍然会留在缓冲区中。        

清空缓冲区

1、getchar():一次只能读取一个一个字符,有时需要连续读取才能清空缓冲区。

优化:这段代码会把键盘缓冲区中的所有字符包括回车字符也读取掉

int tmp = 0;

while ((tmp = getchar()) != '\n')
{
	;//空语句
}

实测在vs2022中{  }中间有无 ; 均可。

2、scanf("%*[^\n]%*c"):先将缓冲区中\n以前的字符取出,最后再将\n取出,清空缓冲区。

scanf返回值

返回成功读入的数据项数,读取失败时(读取类型和输入类型冲突)返回0,读入数据时遇到了“文件结束”则返回EOF(-1)。若输入的第一个值无效时,无论后面两个输入值是否有效,返回值均为0

如:scanf("%d %d",&a,&b); 函数返回值为int型。如果a和b都被成功读入,那么scanf的返回值就是2;如果只有a被成功读入,返回值为1;如果a和b都未被成功读入,返回值为0;如果遇到错误或遇到end of file,返回值为EOF。end of file为Ctrl+z 或者Ctrl+d。

扫描集

%[  ] 扫描集:扫描集定义一个字符集合,可以由scanf 读入允许的字符并赋值给对应的字符数组。它是由一对方括号定义的一串字符定义,方括号左。边必须是百分号

规则:从左到右依次读取,当输入值与方括号内字符不同时就会停止读取。例:scanf("%[ABC]",arr},输入ABDE,输出AB。为了简化字符集合的写法,scanf() 支持使用连字符 - 来表示一个范围内的字符,例如 %[a-z]、%[0-9] 等。

它也可以连续输入字符串,这就要用 ‘^‘ 字符来修饰,可以理解为"补集"

意思就是扫描除方括号内字符的其他字符。扩展:1、想连续输入中间有空白的字符串时,可以用scanf("%[^\n]")。2、清空缓冲区的第二种方法。

难点(空格问题)

1、scanf("%d %c")或scanf("%s %c"):%c前加空格可以吸收缓冲区里的空格。

2、scanf("%d ”):%d后有空格表示输入一个整数后还应该有个任意符号来满足那个空格,唯独不能用回车符来满足这个空格,回车符作为空格被读入,但是后面输入的作为行结束标志的回车符就不会被读到程序中。scanf("%d %d/n",&a,&b):同上述情况随便再输入什么东西来满足这个回车号

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值