C语言scanf函数奇遇记

原创 2012年03月26日 13:16:31
看《The C Programming Language》中关于scanf函数部分时随意敲了几行代码,本以为简单的不得了,都有点“不屑于”敲,却没想到这一敲竟然敲出个不小的问题,涉及到好多东西啊,哈哈!下面把我这次的经历和大家分享一下,希望也能对大家有所帮助。

    一、代码实例

    我当时敲的代码:

    点击(此处)折叠或打开

    #include<stdio.h>

    int main()

    {

    int a;

    int b;

    char mon[20];

    int count;

    count = scanf("%d,%s,%d", &a,mon,&b);

    printf("%d,%s,%d\n",a,mon,b);

    printf("%d\n",count);

    return 0;

    }

    运行结果:

    ocean@ocean-desktop:~/桌面$ ./re

    12,fefe,45   /*这是我的输入*/

    12,fefe,45,10359588

    2

    结果看起来挺像我们想要的结果的,只是最后多了个奇怪的数字;但仔细看下count的值我们就纳闷了,怎么是2不是3呢?怎么scanf只读了两个值?到底怎么回事呢?先用gdb调试一下吧,看看a和mon里都是些什么。

    二、GDB调试情况

    (gdb) p a

    $1 = 12

    (gdb) p mon

    $2 = "fe,45\000\377\277\245\324\025\000\060\340\021\000K\205\004\b"

    明白了吧?原来fe,45作为一个整体被存到mon里了,b根本没读到值,显示了个原内存里的乱七八糟的数值(不相信的话可以在程序开头给b赋个值,最后结果肯定是输出当初赋的值,因为根本没有给b读入新的值),scanf真的只读了两个值,所以count显示2。那为什么会这样呢?让我们来看看scanf函数的相关信息吧。

    三、scanf函数工作原理

    scanf()是从输入流缓冲区中读取值的,而并非从键盘(也就是终端)缓冲区读取。往输入流缓冲区送数据是遇到回车(\n)而结束的,这个\n会一起读入输入流缓冲区。scanf() 开始读取输入以后,会在遇到的第一个空白字符空格(blank)、制表符(tab)或者换行符(newline)处停止读取。

    格式控制字符串中有普通字符(非格式字符)时,这些字符作为输入数据的分隔符,在scanf函数读入数据时自动去掉。

    scanf()格式控制字符串中如果使用%s说明符,那么空白字符以外的所有字符都是可以接受的,所以scanf() 跳过空白字符直到遇到第一个非空白字符,然后保存再次遇到空白字符之前的所有非空白字符。这就意味着%s使scanf() 读取一个单词,也就是说,一个不包含空白字符的字符串。

    好,让我们分析下上述的结果是如何出现的吧。

    四、原因分析

    首先,scanf()跳过空白字符(这里没有,因为第一个字符就是1)直到遇到一个非空白字符1,然后继续读2,读到逗号这个非数字符号时scanf知道整数读完了,将12赋给a,此时输入流缓冲区中第一个开头的字符是逗号;scanf继续读,读到逗号与格式控制字符串的逗号匹配,pass;从f继续读,一直读到下一个空白符——我们结束时敲的回车(scanf自动把这个回车符去掉了,没有送到字符串里),字符串读完了,此时输入流缓冲区里第一个开头的字符是我们敲的回车符;继续读,回车符与格式控制字符串里的逗号不批配,读取失败,不读了。   综上所述,scanf确实只读了一个整数和一个字符串,返回值是2。

    那有什么办法实现用逗号作为间隔符的情况呢?下面提供两种方法:

    五、解决方法

    法1:

    scanf("%d,%[^,],%d", &a,mon,&b);

    printf("%d,%s,%d\n",a,mon,b);

    相关知识:scanf中一种很少见但很有用的转换字符:[…]和[ ^…]

    %[…]如果输入的字符属于方括号内字 符串中某个字符,那么就提取该字符;如果一经发现不属于就结束提取。%[^…]如果一经发现输入的字符属于方括号内字符串中某个字符,那么就结束提取;如果不属于就提取该字符。这两种方法会自动加上一个字符串结束符到已经提取的字符后面。例如:

    点击(此处)折叠或打开

    #include<stdio.h>

    main()

    {

    char strings[100];

    scanf("%[1234567890]",strings);

    printf("%s",strings);

    return 0;

    }

    运行,输入:1234werew后,结果是:1234。

    采用这种方法,读完fefe后遇到逗号便结束字符串的读取,继续读时输入流缓冲区的逗号与格式控制字符串中逗号刚好匹配,成功!

    法2(不够彻底):

    scanf("%d,%s ,%d", &a,mon,&b);   /*注意%s后面有个空格 */

    printf("%d,%s,%d\n",a,mon,b);

    并且在输入时加个空格

    12,fefe ,45   /*fefe和逗号之间加个空白*/

    相关知识:当scanf()格式控制字符串中出现空白时,表示取数时跳过任何空白。

    scanf读到fefe后的空格后结束字符串的读取,此时输入流缓冲区第一个字符为空格;继续读,由于格式控制字符串里有个空格,所以读取时会跳过任何空白(不信可以在fefe后面多敲几个空白试试,全都跳过,甚至连回车都跳过),读到逗号匹配成功。

C语言scanf函数奇遇记

C语言scanf函数奇遇记 作者:ocean    撰写日期:2011-11-20 博客链接:http://oceanspace.tk     看《The C Programming Langu...

黑马程序员-ios学习笔记-C语言scanf函数

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ------- 越先定义的变量地址越大 内存寻址有大到小,优先分配内存地址比较大的字节给变量 取得变量地址;&变...

C语言scanf函数输入时键盘缓冲区\n的问题[经典问题]

程序时对scanf在键盘缓冲区留下的字符有疑问,思考不果。看了百度百科上的scanf词条,说scanf输入遇到空格、跳格、回车才会从缓冲区往变量送字符。于是自己写了以下几个程序思考,还是不果。 ...

浅解C语言中scanf函数

函数原型: #include《stdio.h> int scanf(const char *format,...) scanf()函数是格式化输入函数,它从标准输入设备读取信息。 返回值: ...

黑马程序员-IOS-C语言基础-scanf函数

-------------------------------------- android培训、java培训、ios培训期待与您交流! ------------------------------...

黑马程序员——c语言基础:scanf函数

1.scanf函数的介绍及使用 1)scanf函数是一个阻塞式函数:函数执行后,会等待用户输入,如果用户不输入任何内容,它会一直等待。 2)scanf函数的作用:接收用户从键盘输入的内容,并保存到...

C语言Scanf函数剖析以及数字求和算法

在C语言里,字符的输入都是通过调用函数来实现的:getchar( )、scanf( ) 其中,getchar 函数只能处理单个字符的输入与输出,函数体本质上与scanf函数是一致的,都是阻塞式函数。...

C语言—scanf函数、sizeof、三木运算、各种运算符

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ------- ---scanf函数 1.scanf函数的基本使用 #include in...

【C语言】05-printf和scanf函数

本文目录 一、printf函数二、scanf函数 说明:这个C语言专题,是学习iOS开发的前奏。也为了让有面向对象语言开发经验的程序员,能够快速上手C语言。如果你还没有编程经验,或者对...

iOS笔记:第二篇 C语言scanf函数、变量和运算符

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ------- 第一节  scanf函数 一、scanf函数的作用和语法 1>作用:可以在程序运行的时候让用户...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C语言scanf函数奇遇记
举报原因:
原因补充:

(最多只允许输入30个字)