scanf 函数的使用
<p style="text-indent: 2em;">最近写一个小程序需要用到scanf()函数,发现scanf()函数虽然简单,但是使用起来还是有点小困难,这里我就结合自己的使用以及网上的一些内容,讲一些关于scanf()函数的小知识,博主觉得还是挺有用的哦<img src="/UEditor/dialogs/emotion/images/face/i_f29.gif"/>。</p><p style="text-indent: 2em;">scanf函数与printf函数一样,都被定义在头文件stdio.h里,因此在使用scanf函数时要加上#include <stdio.h>。它是格式输入函数,即按用户指定的格式从键盘上把数据输入到指定的变量之中。</p><p class="artical_littlestyle1">1、基本说明</p><p style="text-indent: 2em;">scanf函数调用形式为: scanf(“<格式说明字符串>”,<变量地址>);变量地址要求有效,并且与格式说明的次序一致。</p><p style="text-indent: 0em;"><span style="color: rgb(0, 112, 192);">(1)、格式说明符</span></p><p style="text-indent: 2em;">转换字符(就是%后跟的部分)</p><p style="text-indent: 2em;">a 读浮点值(仅适用于 C++)</p><p style="text-indent: 2em;">A 读浮点值(仅适用于 C++)</p><p style="text-indent: 2em;">c 读单字符</p><p style="text-indent: 2em;">d 读十进制整数</p><p style="text-indent: 2em;">i 读十进制、八进制、十六进制整数</p><p style="text-indent: 2em;">e 读浮点数</p><p style="text-indent: 2em;">E 读浮点数</p><p style="text-indent: 2em;">f 读浮点数</p><p style="text-indent: 2em;">F 读浮点数(仅适用于 C++)</p><p style="text-indent: 2em;">g 读浮点数</p><p style="text-indent: 2em;">G 读浮点数</p><p style="text-indent: 2em;">o 读八进制数</p><p style="text-indent: 2em;">s 读字符串</p><p style="text-indent: 2em;">x 读十六进制数</p><p style="text-indent: 2em;">X 读十六进制数</p><p style="text-indent: 2em;">p 读指针值</p><p style="text-indent: 2em;">n 至此已读入值的等价字符数</p><p style="text-indent: 2em;">u 读无符号十进制整数</p><p style="text-indent: 2em;">[ ] 扫描字符集合</p><p style="text-indent: 2em;">% 读 % 符号(百分号)</p><p style="text-indent: 2em;">格式说明符的修饰符说明</p><p style="text-indent: 2em;">L/l 长度修饰符 输入”长”数据</p><p style="text-indent: 2em;">h 长度修饰符 输入”短”数据</p><p style="text-indent: 2em;">W 整型常数 指定输入数据所占宽度</p><p style="text-indent: 2em;">* 表示本输入项在读入后不赋值给相应的变量</p><p style="text-indent: 0em;"><span style="color: rgb(0, 112, 192);">(2)、空白符</span></p><p style="text-indent: 2em;">空白字符会使scanf()函数在读操作中略去输入中的一个或多个空白字符。</p><p style="text-indent: 2em;">控制串中的空白符使scanf() 在输入流中跳过一个或多个空白行。空白符可以是空格(space)、制表符(tab)和新行符(newline)。本质上,控制串中的空白符使scanf() 在输入流中读,但不保存结果,直到发现非空白字符为止。</p><p style="text-indent: 0em;"><span style="color: rgb(0, 112, 192);">(3)、非空白符</span></p><p style="text-indent: 2em;">一个非空白字符会使scanf()函数在读入时剔除掉与这个非空白字符相同的字符。</p><p style="text-indent: 2em;">非空白符使scanf()在流中读一个匹配的字符并忽略之。例如,”%d,%d”使 scanf()先读入一个整数,读入中放弃逗号,然后读另一个整数。如未发现匹配,scanf()返回。</p><p style="text-indent: 0em;"><span style="color: rgb(255, 0, 0);">说明:</span></p><p style="text-indent: 2em;"><span style="background-color: rgb(118, 146, 60); color: rgb(0, 0, 0);">1)、</span>百分号(%)与格式符之间的星号(*)表示读指定类型的数据但不保存。因此,<span style="color: rgb(255, 0, 0);">scanf(“%d%*c%d”,&x,&y);</span> 对<span style="color: rgb(255, 0, 0);">10/20</span>的读入操作中,10放入变量 x,20放入 y,’/’不保存。</p><p style="text-indent: 2em;"><span style="background-color: rgb(118, 146, 60);">2)、</span>虽然空格、制表符和新行符都用做域分割符号,但在读单字符操作中却按一般字符处理。例如,对输入流”<span style="color: rgb(255, 0, 0);">x y</span>“调用:<span style="color: rgb(255, 0, 0);">scanf(“%c%c%c”,&a,&b,&c);</span>返回后,x在变量a中,空格在变量b中,y在变量c中。</p><p style="text-indent: 2em;"><span style="background-color: rgb(118, 146, 60);">3)、</span>控制串中的其它字符,包括空格、制表符和新行符,都用于从输入流中匹配并放弃字符,被匹配的字符都放弃。例如,给定输入流”<span style="color: rgb(255, 0, 0);">10t20</span>“,调用:<span style="color: rgb(255, 0, 0);">scanf(“%dt%d”,&x,&y); </span>将把10和20分别放到x和y中,t被放弃,因为t在控制串中。</p><p class="artical_littlestyle2">2、scanf()函数中%[]格式控制符用法</p><p style="text-indent: 2em;">此格式控制符的基本格式为:<span style="color: rgb(255, 0, 0);">%[scanfset]</span></p><p style="text-indent: 2em;">scanfset 有两种形式:</p><p style="text-indent: 2em;"><span style="background-color: rgb(118, 146, 60);">a、</span>一种是以非“^”字符开头的scanset,表示在读入字符串时将匹配所有在scanfset中出现的字符,<span style="color: rgb(255, 0, 0);">遇到非scanfset中的字符时输入就结束</span>;</p><p style="text-indent: 2em;"><span style="background-color: rgb(118, 146, 60);">b、</span>另外一种形式是以“^”字符开头的scanfset,表示在读入字符串时将匹配所有不在scanfset中出现的字符,<span style="color: rgb(255, 0, 0);">遇到scanfset中的字符输入就结束</span>。</p><p style="text-indent: 2em;">scanfset中的’-’连接符:</p><p style="text-indent: 2em;">当“-”出现在scanfset中且两边都有字符时,大多数编译器都做了如下所述实现:“-”表示匹配从其左边的字符到右边字符之间所有的字符(按ASCII码排序)。如a-z表示a到z的所有字符,又如0-9表示0到9这十个数字。所以,当scanfset为0-9时表示只匹配数字串,当scanfset为A-Za-z时表示只匹配字母(包括大小写),当scanfset为^0-9时不匹配所有数字。<span style="color: rgb(255, 0, 0);">注意:</span>“-”的字符只有在其左右两边都有有效字符时才有这个作用,否则被认为是普通字符,如“0-4-6-9”匹配的字符为{0,1,2,3,4,-,6,7,8,9},这样也为输入“-”字符提供了方法。</p><p style="text-indent: 0em;"><span style="background-color: rgb(118, 146, 60);">例1:</span>遇到非小写字母输入结束</p><pre class="brush:cpp;toolbar:false PrismJs">#include <stdio.h>
int main(void)
{
char str[80];
printf("Please input the data:");
//只匹配a-z(小写字母),遇到非小写字母的字符时输入就结束
scanf("%[a-z]",str);//输入:abcdeGfg,那么最终str="abcde"
printf("str:%s",str);
return 0;
}</pre><p style="text-align:center"><img src="/uploads/AilsonJack/2018.08.21/1534862301929087.png" onclick="preview_image('/uploads/AilsonJack/2018.08.21/1534862301929087.png')"/></p><p style="text-indent: 0em;"><span style="background-color: rgb(118, 146, 60);">例2:</span>遇到回车键输入结束<br/></p><pre class="brush:cpp;toolbar:false PrismJs">#include <stdio.h>
int main(void)
{
char str[80];
printf("Please input the data:");
//遇到回车键时,输入就结束
scanf("%[^\n]",str);//输入:ab cd efg
printf("str:%s",str);
return 0;
}</pre><p style="text-align:center"><img src="/uploads/AilsonJack/2018.08.21/1534862302751163.png" onclick="preview_image('/uploads/AilsonJack/2018.08.21/1534862302751163.png')"/></p><p style="text-indent: 2em;">当要匹配右侧’]’或者’^’时,得这样去做。如果是右侧方括号时,得把它放在紧跟在左侧方括号的后边,也不可以有空格,如:%[]ajdfidfj ];如果是’^’时,把它放在除了紧跟在左侧方括号后边的其它位置,如:%[ gfadhfu^fhgiu ] 。</p><p style="text-indent: 0em;"><span style="background-color: rgb(118, 146, 60);">例3:</span>匹配’[’和’^’可用</p><pre class="brush:cpp;toolbar:false PrismJs">#include <stdio.h>
int main(void)
{
char str[80];
printf("Please input the data:");
//遇到除了abcefg^]之外的其它字符,输入就结束
scanf("%[]abc^efg]",str);//输入:a]bc^e fg
printf("str:%s",str);
return 0;
}</pre><p style="text-indent: 2em;">上述代码输入: <span style="color: rgb(255, 0, 0);">a]bc^e fg</span>,由于e与fg之间有空格,空格不属于scanfset中的字符,因此输入就结束了,程序打印出<span style="color: rgb(255, 0, 0);">a]bc^e</span>。</p><p style="text-align:center"><img src="/uploads/AilsonJack/2018.08.21/1534862301396867.png" onclick="preview_image('/uploads/AilsonJack/2018.08.21/1534862301396867.png')"/></p><p class="artical_littlestyle3">3、如何让scanf()函数正确接受有空格的字符串?</p><p style="text-indent: 2em;">如何让scanf()函数正确接受有空格的字符串?如: I love you!</p><pre class="brush:cpp;toolbar:false PrismJs">#include <stdio.h>
int main(void)
{
char str[80];
printf("Please input the data:");
scanf("%s",str);//输入:I LOVE YOU!
printf("%s",str);
return 0;
}</pre><p style="text-align:center"><img src="/uploads/AilsonJack/2018.08.21/1534862301994154.png" onclick="preview_image('/uploads/AilsonJack/2018.08.21/1534862301994154.png')"/></p><p style="text-indent: 2em;"><span style="color: rgb(255, 0, 0);">上述程序并不能达到预期目的,scanf()扫描到”I”后面的空格就认为对str的赋值结束,并忽略后面的”love you!”</span>。这里要注意是”love you!”还在stdin流中(关于这个问题,网上我所见的说法都是在键盘缓冲区,但是,我经过调试发现,其实这时缓冲区字符串首尾指针已经相等了,也就是说缓冲区清空了,scanf()函数应该只是扫描stdin流,这个残存信息是在stdin中)。我们改动一下上面的程序来验证一下:</p><pre class="brush:cpp;toolbar:false PrismJs">#include <stdio.h>
#include <windows.h>
int main(void)
{
char str[80],str1[80],str2[80];
printf("Please input the data:");
scanf("%s",str);/*此处输入:I love you!*/
printf("%s\n",str);
Sleep(5000);/*这里等待5秒,告诉你程序运行到什么地方*/
/*不是sleep(5)
1:函数名是Sleep不是sleep;
2:C/C++中,unsigned Sleep(unsigned)应该是毫秒ms.
*/
scanf("%s",str1);/*这两句无需你再输入,是对stdin流再扫描*/
scanf("%s",str2);/*这两句无需你再输入,是对stdin流再扫描*/
printf("%s\n",str1);
printf("%s",str2);
return 0;
}</pre><p style="text-align:center"><img src="/uploads/AilsonJack/2018.08.21/1534862301263424.png" onclick="preview_image('/uploads/AilsonJack/2018.08.21/1534862301263424.png')"/></p><p style="text-indent: 2em;">好了,原因知道了,所以结论是:残留的信息 love you是存在于stdin流中,而不是在键盘缓冲区中。那么scanf()函数能不能完成这个任务?回答是:能!别忘了scanf()函数还有一个 %[] 格式控制符(如果对%[]不了解的请查看本文的开始部分),请看下面的程序:</p><pre class="brush:cpp;toolbar:false PrismJs">#include <stdio.h>
int main(void)
{
char str[50];
printf("Please input the data:");
//遇到回车键,输入才结束(空格不能让输入结束)
scanf("%[^\n]",str);//输入:I love you!
printf("%s",str);
return 0;
}</pre><p style="text-align:center"><img src="/uploads/AilsonJack/2018.08.21/1534862301188658.png" onclick="preview_image('/uploads/AilsonJack/2018.08.21/1534862301188658.png')"/></p><p class="artical_littlestyle4">4、用“空格符”来处理缓冲区残余信息</p><p style="text-indent: 0em;"><span style="background-color: rgb(118, 146, 60);">例1:</span>没使用空格控制符</p><pre class="brush:cpp;toolbar:false PrismJs">#include <stdio.h>
int main(void)
{
int i;
char ch;
printf("Please input the data:");
//输入:0 1 2 3 4 5 6 7 8 9
for(i=0;i<10;i++)
{
scanf("%c",&ch);/*这里%前没有空格*/
printf("%c",ch);/*打印得到的字符(这里面包含了空格)*/
}
printf("!");//为了显示出前面是否有空格
return 0;
}</pre><p style="text-align:center"><img src="/uploads/AilsonJack/2018.08.21/1534862302370323.png" onclick="preview_image('/uploads/AilsonJack/2018.08.21/1534862302370323.png')"/></p><p style="text-indent: 2em;">输出:0 1 2 3 4 ,数字加空格正好为10,和程序中scanf函数执行了10次是匹配的。<br/><span style="background-color: rgb(118, 146, 60);">例2:</span>使用了空格控制符<br/></p><pre class="brush:cpp;toolbar:false PrismJs">#include <stdio.h>
int main(void)
{
int i;
char ch;
printf("Please input the data:");
//输入:0 1 2 3 4 5 6 7 8 9
for(i=0;i<10;++i)
{
scanf(" %c",&ch);/*注意这里%前有个空格*/
printf("%c",ch);/*打印得到的字符(这里面就不包含空格了)*/
}
printf("!");//为了显示出前面是否有空格
return 0;
}</pre><p style="text-align:center"><img src="/uploads/AilsonJack/2018.08.21/1534862302948055.png" onclick="preview_image('/uploads/AilsonJack/2018.08.21/1534862302948055.png')"/></p><p style="text-indent: 2em;">那么为什么例2就正确呢,原因何在,在%前面加一个空格就这么有用,答案是肯定的,就是%前面的空格在起作用,在scanf的使用过程中应注意的问题中(这些内容在下面)已经指出:“scanf()的格式控制串可以使用空白字符或其它非空白字符,使用空白字符会使scanf()函数在读操作中略去输入中的零个或多个空白字符。”</p><p class="artical_littlestyle1">5、使用scanf函数应注意的问题</p><p style="text-indent: 2em;"><span style="background-color: rgb(118, 146, 60);">1)、</span>对于字符串数组或字符串指针变量,由于数组名和指针变量名本身就是地址,因此使用scanf()函数时,不需要在它们前面加上”&”操作符。</p><p style="text-indent: 2em;"><span style="background-color: rgb(118, 146, 60);">2)、</span>可以在格式化字符串中的”%”各格式化规定符之间加入一个整数,表示任何读操作中的最大位数。</p><p style="text-indent: 2em;"><span style="background-color: rgb(118, 146, 60);">3)、</span>scanf()函数中没有精度控制。</p><p style="text-indent: 2em;">如:<span style="color: rgb(255, 0, 0);">scanf(“%5.2f”,&a);</span> 是非法的。不能企图用此语句输入小数为2位的实数。</p><p style="text-indent: 2em;"><span style="background-color: rgb(118, 146, 60);">4)、</span>scanf中要求给出变量地址,如给出变量名则会出错</p><p style="text-indent: 2em;">如:<span style="color: rgb(255, 0, 0);">int a;scanf(“%d”,a);</span>是非法的,应改为<span style="color: rgb(255, 0, 0);">scanf(“%d”,&a);</span>才是合法的。</p><p style="text-indent: 2em;"><span style="background-color: rgb(118, 146, 60);">5)、</span>在输入多个数值数据时,若格式控制串中没有非格式字符作输入数据之间的间隔,则可用空格,TAB或回车作间隔。C编译在碰到空格,TAB,回车或非法数据(如对“%d”输入“12A”时,A即为非法数据)时即认为该数据结束。</p><p style="text-indent: 2em;"><span style="background-color: rgb(118, 146, 60);">6)、</span>在输入字符数据(%c)时,若格式控制串中无非格式字符,则认为所有输入的字符均为有效字符</p><p style="text-indent: 2em;">如:<span style="color: rgb(255, 0, 0);">scanf(“%c%c%c”,&a,&b,&c);</span></p><p style="text-indent: 2em;">输入:<span style="color: rgb(255, 0, 0);">d e f</span></p><p style="text-indent: 2em;">则把’d’赋予a, ‘ ‘(空格)赋予b,’e’赋予c。因为%c只要求读入一个字符,后面不需要用空格作为两个字符的间隔,因此把’ ‘作为下一个字符送给b。只有当输入为:def(字符间无空格)时,才能把’d’赋于a,’e’赋予b,’f’赋予c。如果在格式控制中加入空格作为间隔:</p><p style="text-indent: 2em;">如:<span style="color: rgb(255, 0, 0);">scanf(“%c %c %c”,&a,&b,&c); </span>则输入时各数据之间可加空格。</p><p style="text-indent: 2em;"><span style="background-color: rgb(118, 146, 60);">7)、</span>如果格式控制串中有非格式字符则输入时也要输入该非格式字符。</p><p style="text-indent: 2em;">如:<span style="color: rgb(255, 0, 0);">scanf(“%d,%d,%d”,&a,&b,&c);</span></p><p style="text-indent: 2em;">其中用非格式符 ’,’ 作间隔符,故输入时应为:<span style="color: rgb(255, 0, 0);">5,6,7</span></p><p style="text-indent: 2em;">又如:<span style="color: rgb(255, 0, 0);">scanf(“a=%d,b=%d,c=%d”,&a,&b,&c);</span></p><p style="text-indent: 2em;">则输入应为:<span style="color: rgb(255, 0, 0);">a=5,b=6,c=7</span><br/></p><p class="artical_littlestyle2">6、小程序</p><p style="text-indent: 2em;">这个小程序主要完成对输入的一系列数据进行求和:</p><pre class="brush:cpp;toolbar:false PrismJs">#include <stdio.h>
int main(void)
{
char ch;
int sum = 0;
int tmp = 0;
printf("please input the number:");
scanf("%c",&ch);
while(ch != '\n')//判断是否读到回车符,表示输入结束
{
if(ch != ' ')//不等于空格,忽略空格
{
tmp = ch - '0';//将ASCII码转换为整数
sum += tmp;//对输入的数据求和
printf("ch:%c\ttmp:%d\r\n",ch,tmp);//打印信息
}
scanf("%c",&ch);//再次取得缓冲区中的数据
}
printf("sum:%d",sum);
return 0;
}</pre><p style="text-align: center;"><img src="/uploads/AilsonJack/2018.08.21/1534862301726395.png" onclick="preview_image('/uploads/AilsonJack/2018.08.21/1534862301726395.png')"/></p>
暂无评论,要不要来个沙发
发表评论
JLink V9掉固件修复(灯不亮) 3Zephyr笔记2 - 在STM32F429上运行HelloWorld 2计算NandFlash要传入的行地址和列地址 1Linux MMC子系统 - 6.eMMC 5.1工作模式-设备识别模式 0Linux MMC子系统 - 5.eMMC 5.1工作模式-引导模式 0Linux MMC子系统 - 4.eMMC 5.1常用命令说明(2) 0
标签云
Linux嵌入式实用技巧ARM内核学习问题集合CC++编程语言阅读笔记汇编Linux内核完全注释Windows驱动开发计算机基础ARM11ARMv7-ASTM32IDESublimeLinux内核学习eMMCMMC子系统Ubuntu操作系统OfficeVMWareAPUEgccRTOS中断漫游世界随笔感悟开发工具软件应用编程VsCodearmccarmclang编译器ZephyrSPIJLink网卡驱动安装各种芯片库函数NFSμCOS内核sambaFlashUnix命令与脚本输入法Linux内核设计与实现gitRIFFWAVJATGFTPar8161安装centos有线上网μCGUI字库工程建立右键菜单网络文件系统Firefox百度NTFS文件系统CodeBlocksCentOS数据结构算法PhotoShop51KeilQTUltraEditscanfglibc宏定义UIDGID优先级娱乐天地SourceInsight磁盘扇区总线I2CPDFBComparePythonI2SFPUMakefileSWDCPUARP软件推荐FileZilla