>第 8 章 数组>多维数组

陈杨希 fusang12@126.com
2009-07-04 13:16:28

在“剪刀石头布”游戏中如果输入一个字母,会进入死循环。。


宋劲杉 songjinshan@akaedu.org
2009-07-09 08:54:53

多谢你发现这个问题!原因是scanf扫描的输入不匹配则不会读走,下次循环这个字母还在,还读不走,再下次循环这个字母还在……要避免这个问题目前没啥好办法,只能是出错就终止程序了。讲到后面可以先用fgets读上来再用sscanf扫描。


陈杨希 fusang12@126.com
2009-07-10 06:25:37

我是学软件测试的。。所以经常会搞些这种去试。
正常的应该是让你输入整数你就不应该输入字母或者其他字符,但软件应该有个容错功能。。我觉得可以把那个scanf("%d",&man)改成scanf("%c",&man)用它的asc码来判断。。内存出错我也用过一个fflush(stdin)来清空。。这个函数是怎么实现的我不知道,只知道他可以用。。班门弄斧了,见笑见笑。


宋劲杉 songjinshan@akaedu.org
2009-07-12 13:12:50

你的意见非常对,但是scanf("%c"...)实在不是好玩的,要费更多唇舌才能解释清楚。scanf在标准库一章会详细解释,在这一章为了避免跑题,还是用这个不怎么容错的办法吧。


陈杨希 fusang12@126.com
2009-07-14 19:06:54

今天又想到一种方法。。可以一试哦~这回不要用scanf("%c"...)。

flag=1;
while(flag){
fflush(stdin);
flag=0;
x=99999;//设置一不太可能用到的数
if(x==999999)
{
  flag=1
}
}


zhoudy dongyong800@163.com
2009-08-01 10:40:34

十分同意并欣赏:“数据代替了代码,数据驱动的编程(Data-driven Programming)"
“剪刀石头布”游戏的结果裁决也可以利用这个原理:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{

    char game_type[3][8]={"scissor", "stone", "cloth"};
    char result_type[3][13]={"Draw", "Computer win", "Human win"};
    int computer_choice,human_choice;
    int ret,result;

    while(1){
        //computer choice
        computer_choice = rand()%3;
        //human choice
        do{
            printf("Please input your choice.0 for scissor, 1 for stone, 2 for cloth \n");
            ret = scanf("%d",&human_choice);
        }while(human_choice >2||human_choice<0);

        //Judgment of choise
        printf("Computer choose:%s\n",game_type[computer_choice]);
        printf("human choose:   %s\n",game_type[human_choice]);

        //Judgment of  result
        result= ((computer_choice - human_choice) + 3) % 3;
        printf("Game result:%s\n",result_type[result]);

    }

    return 0;
}



码匠 code_smith@sohu.com
2009-09-04 14:08:10

(man - computer + 4) % 3 - 1神奇

I know somebody see it as natural,
but for me, the expression makes me lunatic.

plus 4 bracket modulo 3 minus 1
  I collapse!

Who can talk about the secret of the statement?


lonny lonny_liu@hotmail.com
2009-09-18 09:54:06

我也不知道(man - computer + 4) % 3 - 1这个算式怎么想出来的?为什么会达到这个效果,宋老师,能否解答一下?谢谢!


宋劲杉 songjinshan@gmail.com
2009-09-24 22:29:16

这个其实没有多复杂。再仔细想想吧。把所有可能情况下每一步的计算结果都列出来就明白了。


860284226 860284226@qq.com
2010-02-05 19:47:21

我觉得例8.4的语句 printf("%s\n", days[day]);前面应加上else


宋劲杉 songjinshan@gmail.com
2010-02-27 21:59:49

你说得很对,多谢!在实体书第二次印刷时会改过来的


laciqs 530107999@qq.com
2010-04-27 20:37:01

860284226 860284226说的问题我竟然没注意到,汗死。。。。。。
恩,只是想提醒一下上面的几位朋友,fflush(stdin)结果是C标准未定义的,所以对程序的可移植性有要求时候要注意。


laciqs 530107999@qq.com
2010-04-27 20:39:15

对于这个问题,我常常使用
while (getchar() != '\n')
        continue;
来解决。


牛肉丸 niurow@qq.com
2010-09-21 23:29:32

当玩家输入的是0 电脑是2时候

0-2=-2
-2+4=2
2 mod 3 = 2
2-1 = 1 > 0

玩家获胜。。。。


牛肉丸 niurow@qq.com
2010-09-21 23:39:16

。。。太神奇了。。。

man-c-  2 -1  0  1 -1  0  2  1  0
+4      2  3  4  5  3  4  6  5  4
mod 3   2  0  1  2  0  1  0  2  1
-1      1 -1  0  1 -1  0 -1  1  0


牛肉丸 niurow@qq.com
2010-09-21 23:55:48

大概发现了。。。

剪刀石头布 分别为 0 1 2

剪刀对布   -2 胜
石头对剪刀  1 胜
布对石头    1 胜

石头对剪刀  2 负
剪刀对石头 -1 负
石头对布   -1 负  

-2 和  1 为胜
 2 和 -1 为负
    0    为平

让所有情况大于0 用mod限定


danny nevermoredanny@gmail.com
2011-01-27 17:13:30

例8.4中void print_day(int day)内的if应当有个else配对吧,不然day number取1~7意外的数值时会输出乱码!


sd44 sd44sd44@yeah.net
2011-02-16 14:11:45

fflush(stdin)用来清除输入缓冲区只在ms编译器上有用,这是C标准未定义的,在gcc等编译器上并不支持。。。

剪刀 石头 布分别为0 1 2

人 vs 电脑
只有在man - comp = 1 或 man - comp = -2时才是man win...
result = (man - computer + 4) % 3 - 1
这个公式正好包含了1与-2的情况,且只有这种情况才能让result > 0.... 为1或者2



lingshiying lingshiying@126.com
2011-03-30 09:59:50

-2 和  1 为胜
 2 和 -1 为负
    0    为平

这个可以想的出来,问题是怎么能够通过这个条件想到那个式子!!!


张鑫 onepersonzx@yahoo.com.cn
2011-08-11 23:28:24

result = (man - computer + 4) % 3 - 1
我的理解:
我们简化这个式子,都以结果非负考虑先:
上面的式子等同于:
result = (man - computer + 1) % 3 -1
又等同于:
result = (man - computer);
这个结果就是人选择的下标比computer的下标大1
再看看字符数组:剪刀,石头,布,刚好是后面的一个赢前面的那个。(除去负的情况)
现在,我们需要由
result = (man  -computer)
往上推:正的情况不考虑。
当人=0,PC=2时,也是人赢,这时,我们需要一个不改变式子大小但是要让
(man -computer)非负的操作,没错,就是取余:
result = (man - computer)+1-1;
result = (man - computer+1)-1;
result = (man - computer + 1)%3-1;
result = (man - computer + 4)%3-1;
关于这个式子为什么这个特殊的数字是3,我还没想通..求高人指点


caozhijie czj627@126.com
2012-01-13 17:59:47

if (ret != 1 || man < 0 || man > 2) {
	printf("Invalid input!\n");
	return 1;
}
为什么ret==0 和 ret==2 不会执行上面的打印语句?


caozhijie czj627@126.com
2012-01-13 18:16:09

ret != 1 
好像是在判断ret是不是整数,而不是在判断ret等不等于1?
这是怎么回事?


caozhijie czj627@126.com
2012-01-13 21:21:06

在一条线上均匀展开3种结果:
......输,平,嬴,输,平,嬴......
任意相同结果出现的周期都是2。

(一组连续的整数中的每个数-其中最大的负数+1)%3,得到的结果展开:
......0,1,2,0,1,2.......
任意相同的两数出现的周期是2。

结果=(一组连续的整数中的每个数-其中最大的负数+1)%3
结果==0 执行动作0
结果==1 执行动作1
结果==2 执行动作2

“一组连续的整数中的每个数-其中最大的负数+1”说明:
“连续”表示相邻两数差为1
“-其中最大的负数+1”:如果这是一组连续的正整数就不需要这么做。这么做的目的是为了%3的操作数是正数。


caozhijie czj627@126.com
2012-01-13 21:25:15

所以下面的代码也能实现相同的结果
result = (man - computer + 3) % 3 ;
		if (result == 1)
			printf("You win!\n");
		else if (result == 0)
			printf("Draw!\n");
		else
			printf("You lose!\n");


如果您有建设性意见,哪怕只是纠正一个错别字,也请不吝赐教,您留下的姓名和email将会出现在本书前言的致谢中。再次感谢您的宝贵意见!