猜数字游戏的bug讨论,如何发现并修正bug。

来源:互联网 发布:脖子戴的黑色项圈 知乎 编辑:程序博客网 时间:2024/04/29 17:32

猜数字游戏的bug讨论,如何发现并修正bug

 

作者:jhkdiy

 

    之前大家都看过了《C++编写猜数字游戏》的文章了,整个源代码比较简单,有C++基础就可以看

明白程序的流程,但我的目的并不是在说说简单的C++语法复习和C++的实际应用,而是在于说一

下一直被很多初学者忽略的编程问题:如何发现并修正bug。很多学编程的朋友一般只要在编译时没有

语法错误能编译运行就万事大吉了,这样的不良习惯在以后会很严重。

那么我们一般怎样发现错误呢?错误不外乎这几种情况:第一个肯定是[b]语法错误[/b],这个比较容易解决,

因为一般编译器都会发现这样的错误并有明显的提示,我们只要找到错误行并修正就可以了,错误一般

是无意的拼写错误,符号错误等。

    另一种情况是语法没有错误,但是程序就是没有达到自己预想的结果这一般是[b]逻辑错误[/b],而逻辑错误又

分为两种情况,一种是无意的逻辑错误,例如本来是想一个循环执行10次的,但是错误将结束条件写错了,而

导致执行了更多或更少,这种情况就要自己阅读源代码来解决了,因为自己了解程序的流程,所以一般都比较

容易发现。另一种情况是算法本身有问题,或更通俗的说是解决问题的方法有问题,设计思路有问题,这种情

况算是比较难发现的了。因为既不是语法错误,又不是自己的无意写错,代码更自己设想的流程都一样,但结

果就是不对。这种情况打败了很多编程人员,很多朋友在这种情况下只能到论坛发帖子了,找求救了,但很多

网友也一样爱莫能助。我个人认为这种情况还是自己研究好,当程序到了这种地步的时候就应该思考了:是我

的设计思路有问题吗?这个问题有没有其它方法可以解决?解决问题的方法通常都不止一个,当出现这种情况

的时候就应该考虑使用其它设计思路了。这也意味着一个大问题:你的代码需要重写,这对一般的小程序不成

问题,但如果重写导致整个项目的变动时就麻烦了,所以要慎重。

    还有一种情况是[b]环境错误和系统错误[/b]。这种情况可以说简单,而有时候又不简单。这种错误的表现是程序能

正常编译,但程序一执行就说“非法内存访问”或“此内存不能read”,跟着便是程序崩溃。相信很多朋友都遇过

这种情况,程序员最痛苦的事莫过于此。新手一般不懂得解决这种问题,因为他还不懂得怎样调试程序,这时到论坛

发帖求助是正确的。懂得调试的朋友就比较容易发现错误,当出现内存访问错误对话框时,可以记下导致程序错误

的指令地址,然后用调试软件载入程序,在导致程序错误的指令前下断点来执行,这时通常都会发现问题的所在。

只要修改一下代码就可以了。最后一种情况就是系统本身的问题,这种问题当你不知道原因的时候最难解决,但当

你知道原因的时候却最容易解决,这种情况就是程序的运行环境问题,一般学习语言的时候不会碰到,但编写实际

的应用软件时就会发生了,例如有些API函数只能在NT系列的系统上运行,win9x是不支持的,有很多新手不知道某个

函数的执行平台,老是发帖子问,但很多时候的回复就是简单的“该函数不能在该系统上运行”。解决这样的问题只

有找个替换的方法了,或者使用新的API,或者使用另一种方法。

    错误的表现总是多种多样的,很多时候让人琢磨不透,但当问题解决的那一刹那却无比欣喜。这就是编程,让我

欢喜让我优。当出现问题时要试着自己解决,发现错误并修正它,在这个过程中你会学习到更多有趣的知识,而你的

编程经验也将在这里积累,所以编程能力的提高不单单是编写更多的程序,同时还要懂得调试程序。

    好了,说了这么多,下面就讨论一下这个游戏存在的问题,首先这里不讨论语法错误问题,因为如果出现语法问题

证明你的基础不扎实。那么这个程序到底都有那些问题呢?在解说之前还是再看看代码吧:

[CODE]

/*

*       能:猜数字的游戏

*   编译环境:windows2000 Dev-c++ 4.9

*       者:jhkdiy

*   电子邮件:jhkdiy_gzb@21cn.net

*       注:无意中看到《Beginning C++ game programming》一书,随便浏览了一下,

*             觉得这个游戏有点意思,所以自己完善了下。初学者用来学习一下语法

*             和提高一下兴趣还是很有意思的。该程序有BUG,大家找出来,

*             不是语法错误哦!!思考一下! 

*/

 

#include <cstdlib>

#include <iostream>

#include <ctime>

 

using namespace std;

 

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

{

    //产生随机数种子

    srand(time(0));            

   

    int  theNumber = rand() % 100 + 1;     //随机数控制在1100之间

    int  tries = 0,                        //用户尝试的次数

         guess;                            //用户输入的数字

    char bPlayAgain;                       //是否继续游戏

   

    cout << "/tWelcome to guess my number/n/n";

   

    do

    {

         //接受用户的输入

         cout << "Enter a guess: ";

         cin >> guess;

         ++tries;

        

         //如果输入的数字大于产生的随机数

         if( guess > theNumber )

         {

             cout<<"Too high!/n/n";

         }

        

         //如果输入的数字小于产生的随机数

         if( guess < theNumber )

         {

             cout << "Too low!/n/n";

         }

        

         //猜对了···

         if( guess == theNumber )

         {

             cout << "/n/n/tVery good! you get it!"

                  << "/tThe number is: " << theNumber << endl;

                 

             cout << "/n/n/tyou try " << tries << " times!" << endl;

            

             //是否继续游戏

             cout << "/n/nDo you want to play again?(y/n)";

             cin  >> bPlayAgain;

             if( bPlayAgain == 'y' || bPlayAgain == 'Y')

             {

                 //清屏后继续游戏

                 system("cls");

                 continue;

             }

             else if( bPlayAgain == 'n' || bPlayAgain == 'N')

             {

                 cout << "/nSee you next time, bye!/n";

                 break;            

             }   

             else

             {

                 cout << "/nEnter a wrong choice! program will exit!/n";

                 break;

             }

         }

        

    }while(true);

   

    //退出程序

    system("pause");

    return EXIT_SUCCESS;

}

[/CODE]

 

    程序第一次运行完全没有问题,但很多朋友很快就发现了一个bug,这个bug出现在:

[code]

             //是否继续游戏

             cout << "/n/nDo you want to play again?(y/n)";

             cin  >> bPlayAgain;

             if( bPlayAgain == 'y' || bPlayAgain == 'Y')

             {

                 //清屏后继续游戏

                 system("cls");

                 continue;

             }

[/code]

 

    程序直接清屏后就继续游戏了,竟然忘了,忘了什么?当第二次猜数字猜对的时候尝试

次数明显不对,明明只用4次猜对了,它竟然说尝试了9次。再看看代码,哦,原来在继续下

一次游戏之前没有对tries变量作初始化,这个容易修正:

[code]

             //是否继续游戏

             cout << "/n/nDo you want to play again?(y/n)";

             cin  >> bPlayAgain;

             if( bPlayAgain == 'y' || bPlayAgain == 'Y')

             {

                 //清屏后继续游戏

                 tries = 0;

                 system("cls");

                 continue;

             }

[/code]

     这下应该没问题了吧,第二次猜猜看,第三次猜猜看,咦??怎么每次猜的数字都是一样的?

再看看代码,又是刚才修改过的那段代码,程序中用来保存随机数的变量theNumber只在程序第一次

运行的时候赋值了,当第二次猜数字的时候它根本没有变,所以导致第二次以后的数字都是一样的。

好,知道问题所在后就好办了,继续修正:

[code]

             //是否继续游戏

             cout << "/n/nDo you want to play again?(y/n)";

             cin  >> bPlayAgain;

             if( bPlayAgain == 'y' || bPlayAgain == 'Y')

             {

                 //清屏后继续游戏

                 tries = 0;

                 theNumber = rand() % 100 + 1;     //随机数控制在1100之间

                 system("cls");

                 continue;

             }

[/code]

 

     好了,当程序第一次运行没问题,第二次、第三次也没问题了,自从修好后,腰不酸了,腿不疼了

嘿,还真灵···。真的没问题了吗?没问题啊,程序现在运行的好好的。呵呵,大家忽略了一个事实,

我们都假定用户的输入是可信赖的。问题就在这里,大家看看这段代码:

[code]

         //接受用户的输入

         cout << "Enter a guess: ";

         cin >> guess;

         ++tries;

[/code]

 

     程序假定用户输入的就是我们期望的数字,但是,如果用户输入的不是数字又会如何呢?实际情况吓

我们一跳,程序无限循环,已经无法控制了。这在实际的应用软件中经常出现,这就表明很多软件设计者

都不经意地作了很多假设:只要用户照我的使用方法做程序准没错。但是很多用户就是喜欢搞破坏,喜欢

搞垮程序。我们作为设计者应该要重视这个问题,对用户的输入不作任何自以为是的假设,对输入进行严格

的检查,只有符合程序运行的输入才作处理。那么这个程序应该如何修改呢?很简单,我们要对用户的输入

进行检查,提示用户只能输入数字:

[code]

         //接受用户的输入

         cout << "Enter a guess: ";

         cin >> guess;

        

         //输入数据类型错误,非致命错误,可清除输入缓冲区挽回!

         if( cin.rdstate() == ios_base::failbit )

         {

             system("cls");

             cout << "Please enter numeric value!/n"<< endl;

            

             //使用clear()更改标记为正确后,同时也需要使用get()成员

             //函数清除输入缓冲区,以达到重复输入的目的。

             cin.clear();

             cin.get();

             continue;

            

         }

        

         ++tries;

[/code]

 

    好了,再次编译运行程序,输入非数字字符,哦,程序检测到了,能正常运行。程序共

修改了三次,最后的代码如下:

[code]

/*

*       能:猜数字的游戏

*   编译环境:windows2000 Dev-c++ 4.9

*       者:jhkdiy

*   电子邮件:jhkdiy_gzb@21cn.net

*       注:无意中看到《Beginning C++ game programming》一书,随便浏览了一下,

*             觉得这个游戏有点意思,所以自己完善了下。初学者用来学习一下语法

*             和提高一下兴趣还是很有意思的。该程序有BUG,大家找出来,

*             不是语法错误哦!!思考一下! 

*       正:第二次运行tries变量没初始化,第二次运行theNumber变量没初始化,

*             当用户输入非数字字符时程序崩溃的问题。

*/

 

#include <cstdlib>

#include <iostream>

#include <ctime>

 

using namespace std;

 

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

{

    //产生随机数种子

    srand(time(0));            

   

    int  theNumber = rand() % 100 + 1;     //随机数控制在1100之间

    int  tries = 0,                        //用户尝试的次数

         guess;                            //用户输入的数字

    char bPlayAgain;                       //是否继续游戏

   

    cout << "/tWelcome to guess my number/n/n";

   

    do

    {

         //接受用户的输入

         cout << "Enter a guess: ";

         cin >> guess;

        

         //输入数据类型错误,非致命错误,可清除输入缓冲区挽回!

         if( cin.rdstate() == ios_base::failbit )

         {

             system("cls");

             cout << "Please enter numeric value!/n"<< endl;

            

             //使用clear()更改标记为正确后,同时也需要使用get()成员

             //函数清除输入缓冲区,以达到重复输入的目的。

             cin.clear();

             cin.get();

             continue;

            

         }

         

         ++tries;

        

         //如果输入的数字大于产生的随机数

         if( guess > theNumber )

         {

             cout<<"Too high!/n/n";

         }

        

         //如果输入的数字小于产生的随机数

         if( guess < theNumber )

         {

            

             cout << "Too low!/n/n";

         }

        

         //猜对了···

         if( guess == theNumber )

         {

             cout << "/n/n/tVery good! you get it!"

                  << "/tThe number is: " << theNumber << endl;

                 

             cout << "/n/n/tyou try " << tries << " times!" << endl;

            

             //是否继续游戏

             cout << "/n/nDo you want to play again?(y/n)";

             cin  >> bPlayAgain;

             if( bPlayAgain == 'y' || bPlayAgain == 'Y')

             {

                 //清屏后继续游戏

                 tries = 0;

                 theNumber = rand() % 100 + 1;     //随机数控制在1100之间

                 system("cls");

                 continue;

             }

             else if( bPlayAgain == 'n' || bPlayAgain == 'N')

             {

                 cout << "/nSee you next time, bye!/n";

                 break;            

             }   

             else

             {

                 cout << "/nEnter a wrong choice! program will exit!/n";

                 break;

             }

         }

        

    }while(true);

   

    //退出程序

    system("pause");

    return EXIT_SUCCESS;

}

 

[/code]

 

     总结下,第一个和第二个错误属于逻辑错误,由于编程疏忽大意而造成的,但第三个错误

在用户不输入非数字字符前是永远不会被发现出来的,这就是程序的健壮性问题。

    希望看了这篇文章后对大家有所帮助,有所觉悟,在编程的道路上更进一步。

下面是修改后完整的代码和执行程序。

 

http://jhkdiy.go3.icpcn.com/code/download/gessnumber.rar

 

http://jhkdiy.go3.icpcn.com/code/download/gessnumberfixed.rar

原创粉丝点击