开发者社区> 问答> 正文

关于c语言中scanf()的“%c”格式控制的一个问题:报错

今天在做K&R上面的练习,用scanf()函数写一个简单的后缀计算器,遇到了以下问题:


源程序如下(linux 下 用 gcc编译的):

#include <stdio.h>
main() {
    int a, b, c, temp, temp2;

    a = b = c = 0;
    scanf("%d", &a);
    scanf("%d", &b);
    temp = scanf("%d", &b);
    temp2 = scanf("%c", &c);


    printf("a is : %d\n", a);
    printf("b is : %d\n", b);
    if (c == '\n')
        printf("c is  a <LF>\n");
    else
        printf("c is: %d(%c)\n", c, c);
    printf("temp is : %d\n", temp);
    printf("temp2 is : %d\n", temp2);
}

当我的输入是:

“1 234 *“(星号('*')后面直接跟一个回车,1 和 234 还有 加号之间有个空格)时,

程序的输出为:

1 234 *
a is : 1
b is : 234
c is: 42(*)
temp is : 0
temp2 is : 1

由程序的输出结果,可以分析出,1 和 234 都分别成功赋值给了a和b,在第三次调用scanf()时(temp = scanf("%d", &b)),由于加号(‘*’)并非数字,所以匹配失败,scanf()返回0给temp,表示没有成功匹配和赋值,b还保持原来的值(234)。此时,匹配失败的星号('*')被重新放回缓存区中(其后当然还跟着一个换行符'\n'),所以在最后一次调用scanf()函数时,星号被重新由缓存区中读取出来,与"%c"格式控制符匹配并且匹配成功,于是赋值给了c。成功匹配完参数的scanf()函数返回匹配数 1 给temp2变量。整个main()函数宣告结束,虽然缓存区中还有个换行符没有被读取。

这个过程我都能理解,但是下面的我就很疑惑了:


当我的输入是:

“1 234 +”(加号后面直接跟一个回车,1 和 234 还有 加号之间有个空格)时,

输出为:

a is : 1
b is : 234
c is  a <LF>
temp is : 0
temp2 is : 1

也即是说,1 和 234 都分别成功赋值给了a和b,在第三次调用scanf()时(temp = scanf("%d", &b)),由于加号(‘+’)并非数字,所以匹配失败,scanf()返回0给temp,表示没有成功匹配和赋值,b还保持原来的值,新读取但匹配失败的加号('+')应该放回缓存区中。在最后一次的scanf()的调用中,加号应该会被重新读取并赋值给c,却为何是其后的换行符('\n')被赋值了呢?

在这一点上我十分之不理解。而且经过测试,发现减号(‘-’)也有这个情况,就是当匹配失败时都好像被直接丢弃,而不是向遇到星号和其它符号一样被放回缓存区中等待下次的读取。

这是什么原因呢?请有相关经验的前辈出来说说,替我这个小菜解解惑。Thanks~

展开
收起
kun坤 2020-06-06 15:53:59 621 0
1 条回答
写回答
取消 提交回答
  • 因为 + 和 - 是属于有效输入中的一部分,想一下你要输入正数(可以额外添加+号)或负数。所以它们不会被放回去。

    ######这个理解不错######

    相信这位兄弟没有看过 itoa, atoi 之类的库函数, 看过库函数你就知道了

    so easy

    ######

    引用来自“stxy0509”的答案

    因为 + 和 - 是属于有效输入中的一部分,想一下你要输入正数(可以额外添加+号)或负数。所以它们不会被放回去。

    请问我可以这么理解吗?就是,如果第一个所要进行匹配的字符与格式控制说明相符(在这里,就是“%d”与‘+’或者‘-’相符,因为它们都属于int型十进制的有效输入),但是如果第二个字符并不属于有效输入(这里遇到的换行符),所以停止匹配,开始对所获得的字符串(这里为‘+’)进行转换,由于输入有效但是却因为只有加号所以不能转换成功,所以不能放回缓存区中(因为已经在转换中,能放回的只是未进入转换过程那个多读取的字符)。
    请问我这样理解对吗?
    ######

    恩,是这样的。

    你理解的很具体,很深入,是学编程的好苗子,呵呵。

    ######哈哈,十分感谢前辈,目前的问题已经解决了。对scanf()的理解也加深了不少,果然遇到问题努力解决才是提升的好方法。再次感谢前辈~
    2020-06-06 15:54:04
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载