免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2982 | 回复: 7

[C] scanf的问题 [复制链接]

论坛徽章:
0
发表于 2009-05-22 17:21 |显示全部楼层
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <time.h>
  4 int main(void)
  5 {
  6     char gesture[3][10] = { "scissor", "stone", "cloth" };
  7     int man, computer, result;
  8     srand(time(NULL));
  9     int ret;
10     while (1) {
11             computer = rand() % 3;
12             printf("\nInput your gesture (0-scissor 1-stone 2-cloth):\n");
13             scanf("%d",&man);
14             if (  man < 0 || man > 2) {
15                     fflush(stdin);
16                    printf("Invalid input! Please input 0, 1 or 2.\n");
17                     continue;
18             }
19             printf("Your gesture: %s\tComputer's gesture: %s\n", gesture[man], gesture[computer]);
20             result = (man - computer + 4) % 3 - 1;
21             if (result > 0)
22                   printf("You win!\n");
23               else if (result == 0)
24                       printf("Draw!\n");
25               else
26                       printf("You lose!\n");
27       }
28     return 0;
29 }   


为什么我故意输错(输入字符)continue到下一次循环不会再scanf了呢?就一直判断if(man ……进入死循环了。我刚学C,上面代码来自书<Linux C编程一站式学习>。。

论坛徽章:
4
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:57:09IT运维版块每日发帖之星
日期:2015-09-14 06:20:0015-16赛季CBA联赛之深圳
日期:2016-01-16 16:34:21
发表于 2009-05-22 19:56 |显示全部楼层
运行了你代码,没有出现你描述的问题。

论坛徽章:
0
发表于 2009-05-22 20:04 |显示全部楼层
不再scanf?不太可能吧,我本地试过了可以啊,运行还算正常,没出现什么问题

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2009-05-23 07:50 |显示全部楼层
原帖由 ChinaTelecom 于 2009-5-22 17:21 发表
为什么我故意输错(输入字符


估计回帖的人都没看这句话。

注意检查scanf的返回值。
如果输入错误, scanf并不会将不符合格式需要的字符(比如对于整数,'z'就是)从流中走。
而是将其保留在原处,下一次输入是仍然从这个'z'开始检测。


更详细一点的说, 解析一个int。 一开始输入流中是空的, scanf 会使得控制回到控制台等待输入。
1. 输入 1212
全部被scanf取走, 下一次循环流中又是空的,控制再次回到控制台。

2. 输入 cherrie
scanf会停在第一个不是digit的字符, 'c'。
因为scanf需要读入一个int, 但是一个合法的字符都没读到, 这个int读取是不成功的,所以会返回0。
man保持不变, 同时输入流中的第1个字符依然是'c',不会被取走。

执行scanf下面的语句,用上一次的man进行比较。

然后又开始一个循环, 输入流不为空,所以控制不会转到控制台。
同时, 这是输入流里依然是 cherrie, 会重复2, 就出现死循环了。

3. 输入 1212cherrie
scanf依然会停在 'c',并且不将其从输入流中取走。
与2不同的是,在'c'之前scanf读取了4个digit, 所以读取是成功的, 返回1(成功读取的item数目)。man被写入1212。
输入流还剩cherrie, 然后执行scanf后面的语句。

当下一次循环的时候, 就进入了2.


要改么,  简单的做法可以将不合理的字符忽略掉, 比如将第13行换成:

           for (ret = 0;!ret ; ) {
               switch (scanf("%d",&man) ) {
               case EOF:
                   /* game over */
                   return 0;
               case 0:
                   (void)getchar(); /* 取走一个字符,*/
                   /* 然后在下一个循环中继续读取 */
                   /* 直到EOF;或者下一字符是digit;或者输入流为空,控制回到控制台,以读取更多字符 */
                   break;
               case 1:
                   ret = 1;
                   /* 确实读取到了一个int, 开始下面的游戏 */
               }
           }

[ 本帖最后由 OwnWaterloo 于 2009-5-23 07:54 编辑 ]

论坛徽章:
0
发表于 2009-05-23 08:53 |显示全部楼层
原帖由 OwnWaterloo 于 2009-5-23 07:50 发表


估计回帖的人都没看这句话。

注意检查scanf的返回值。
如果输入错误, scanf并不会将不符合格式需要的字符(比如对于整数,'z'就是)从流中取走。
而是将其保留在原处,下一次输入是仍然从这个'z'开始 ...

看来我们对于scanf的使用理解远远不够透彻阿

论坛徽章:
0
发表于 2009-05-23 09:45 |显示全部楼层

回复 #4 OwnWaterloo 的帖子

谢谢,你的办法是可行的。
我原来设想
ret = scanf("%d",&man);
if(ret != 1)
fflush(stdin);
为什么这样不能清空输入流呢?

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2009-05-23 09:52 |显示全部楼层

回复 #6 ChinaTelecom 的帖子

fflush(stdin) ...
呃 ……  我还把这行看掉了 ………………

对输出, "刷新"比较好理解。 那“刷新”输入流是什么含义……?
控制回到控制台?  丢弃输入流中的字符(楼主是这个意思吧)? 还是别的什么?

其实它可能是这个,也可能是那个,也可能什么都不是 ……
fflush 对输入流的结果是未定义的。


相关链接:
http://cpp.ga-la.com/html/3/3/0510/6.htm

[ 本帖最后由 OwnWaterloo 于 2009-5-23 09:54 编辑 ]

论坛徽章:
0
发表于 2009-05-23 10:07 |显示全部楼层

回复 #7 OwnWaterloo 的帖子

嗯 ,这下明白了,谢谢OwnWaterloo,原来我看的参考是win环境下的。它对fflush有扩展定义。然后我用gcc编译却是无意义的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP