劣质代码评析——《写给大家看的C语言书

2019-08-03 02:20 来源:未知

  下面继续分析这个代码。为了便于说明问题,为代码添加了行号。

前面已经讲完了C语言中的基本语句和基本运算了,这讲呢,介绍C语言中的重头戏---函数。其实函数这个概念,在大部分高级语言中都是非常重要的,我也已经在《第一个C语言程序》一讲中对函数作了一个简单介绍。

美洲杯赌球 1美洲杯赌球 2

一、基本概念

0. #include <stdio.h>  1. #include <time.h>  2. #include <ctype.h>  3. #include <stdlib.h>  4.   5. #define BELL 'a'  6. #define DEALER 0  7. #define PLAYER 1  8.   9. #define ACELOW 0  10. #define ACEHIGH 1  11.   12. int askedForName = 0;  13.   14. void dispTitle(void);  15. void initCardsScreen(int cards[52],int playerPoints[2],  16. int dealerPoints[2], int total[2],   17. int *numCards);  18. int dealCard(int * numCards,int cards[52]);  19. void dispCard(int cardDrawn,int points[2]);  20. void totalIt(int points[2],int tatal[2],int who);  21. void dealerGetsCard(int *numCards,int cards[52],  22. int dealerPoints[2]);  23. void playerGetsCard(int *numCards,int cards[52],  24. int playerPoints[2]);  25. char getAns(char mesg[]);  26. void findWinner(int total[2]);  27.   28. main()  29. {  30.    int numCards;  31.    int cards[52],playerPoints[2],dealerPoints[2],total[2];  32.    char ans;  33.   34.    do   35.    {   36.       initCardsScreen(cards,playerPoints,dealerPoints,total, &numCards);  37.       dealerGetsCard(&numCards,cards, dealerPoints);  38.       printf("n");  39.       playerGetsCard(&numCards,cards,playerPoints);   40.       playerGetsCard(&numCards,cards,playerPoints);  41.       do  42.       {  43.          ans = getAns("Hit or stand (H/S)?");  44.          if ( ans == 'H' )  45.          {   46.             playerGetsCard(&numCards,cards,playerPoints);  47.          }    48.       }  49.       while( ans != 'S' );  50.   51.       totalIt(playerPoints,total,PLAYER);  52.       do  53.       {  54.          dealerGetsCard(&numCards,cards,dealerPoints);  55.       }  56.       while (dealerPoints[ACEHIGH] < 17 );  57.   58.       totalIt(dealerPoints,total,DEALER);  59.       findWinner(total);   60.   61.       ans = getAns("nPlay again(Y/N)?");    62.    }  63.    while(ans=='Y');  64.   65.    return ;  66.   67. }  68.   69. void initCardsScreen( int cards[52],int playerPoints[2],  70.                       int dealerPoints[2], int total[2],   71.                       int *numCards )  72. {  73.    int sub,val = 1 ;  74.    char firstName[15];  75.    *numCards=52;  76.   77.    for(sub=0;sub<=51;sub  )  78.    {  79.       val = (val == 14) ? 1 : val;  80.       cards[sub] = val;  81.       val  ;    82.    }  83.   84.    for(sub=0;sub<=1;sub  )  85.    {   86.       playerPoints[sub]=dealerPoints[sub]=total[sub]=0;  87.    }  88.    dispTitle();  89.   90.    if (askedForName==0)  91.    {   92.       printf("What is your first name?");  93.       scanf(" %s",firstName);  94.       askedForName=1;  95.       printf("Ok, %s,get ready for casino action!nn",firstName);  96.       getchar();  97.    }  98.    return;          99. }  100.   101. void playerGetsCard(int *numCards,int cards[52],int playerPoints[2])  102. {  103.    int newCard;  104.    newCard = dealCard(numCards, cards);  105.    printf("You draw:");  106.    dispCard(newCard,playerPoints);  107. }  108.   109.   110. void dealerGetsCard(int *numCards,int cards[52],int dealerPoints[2])  111. {  112.    int newCard;  113.    newCard = dealCard(numCards,cards);  114.    printf("The dealer draws:");  115.    dispCard(newCard,dealerPoints);  116. }  117.   118. int dealCard(int * numCards,int cards[52])  119. {  120.    int cardDrawn,subDraw;  121.    time_t t;  122.    srand(time(&t));  123.    subDraw = (rand()%(*numCards));  124.    cardDrawn = cards[subDraw];  125.    cards[subDraw] = cards[*numCards -1];  126.    (*numCards)-;  127.    return cardDrawn;  128. }  129.   130. void dispCard(int cardDrawn, int points[2])  131. {  132.    switch(cardDrawn)  133.    {  134.       case(11): printf("%sn","Jack");  135.                 points[ACELOW]  = 10;  136.                 points[ACEHIGH]  = 10;  137.                 break;  138.       case(12): printf("%sn","Queen");  139.                 points[ACELOW]  = 10;  140.                 points[ACEHIGH]  = 10;  141.                 break;  142.       case(13): printf("%sn","King");  143.                 points[ACELOW]  = 10;  144.                 points[ACEHIGH]  = 10;  145.                 break;  146.       default : points[ACELOW]  = cardDrawn;  147.                 if(cardDrawn==1)  148.                 {   149.                    printf("%sn","Ace");  150.                    points[ACEHIGH] = 11;  151.                 }  152.                 else  153.                 {    154.                   points[ACEHIGH] =cardDrawn;  155.                   printf("%dn",cardDrawn);   156.                 }  157.    }  158.    return ;  159. }  160.   161. void totalIt(int points[2],int total[2],int who)  162. {  163.    if ( (points[ACELOW] == points[ACEHIGH])  164.       ||(points[ACEHIGH] > 21 ))  165.    {   166.      total[who] = points[ACELOW];  167.    }  168.    else  169.    {   170.        total[who] = points[ACEHIGH];  171.    }  172.   173.    if (who == PLAYER )  174.    {  175.       printf("You have a total of %dnn", total[PLAYER]);  176.    }  177.    else  178.    {  179.        printf("The house stands with a total of %dnn",   180.        total[DEALER]);  181.    }  182.    return;  183. }  184.   185. void findWinner(int total[2])  186. {  187.    if ( total[DEALER] ==  21 )  188.    {  189.        printf("The house wins.n");  190.        return ;  191.    }  192.    if ( (total[DEALER] > 21) && (total[PLAYER] > 21) )  193.    {   194.       printf("%s", "Nobody wins.n");  195.       return ;   196.    }  197.    if ((total[DEALER] >= total[PLAYER])&& (total[DEALER] < 21))  198.    {   199.       printf("The house wins.n");  200.       return ;   201.    }  202.    if ((total[PLAYER] > 21)&& (total[DEALER] < 21))  203.    {   204.       printf("The house wins.n");  205.       return ;   206.    }  207.    printf("%s%c","You win!n",BELL);  208.    return;  209. }  210.   211. char getAns(char mesg[])  212. {  213.    char ans;  214.    printf("%s", mesg);  215.    ans = getchar();  216.    getchar();  217.    return toupper(ans);  218. }  219.   220. void dispTitle(void)  221. {  222.    int i = 0 ;  223.    while(i<25)  224.    {   225.         printf("n");  226.         i  ;   227.    }  228.    printf("nn*Step right up to the Blackjack tables*nn");  229.    return ;  230. }

1.什么是函数

任何一个C语言程序都是由一个或者多个程序段(小程序)构成的,每个程序段都有自己的功能,我们一般称这些程序段为“函数”。所以,你可以说C语言程序是由函数构成的。

比如你用C语言编写了一个MP3播放器程序,那么它的程序结构如下图所示:

美洲杯赌球 3

  • 从上图可以看出:函数就是用来实现某个功能的程序段,每一个函数都有自己的功能。因此,你应该把实现某个功能所需的代码都写在函数中。比如,有个函数的功能是播放MP3,那么播放MP3的代码都应该写到这个函数中。
  • 当调用(执行)一个函数时,计算机就会按顺序执行函数中的所有代码,从而展示函数所实现的功能。

 

View Code

2.函数名

一般来说,我们会将不同的功能交给不同的函数去实现。比如,将暂停播放MP3的代码写到一个函数中,将停止播放MP3的代码写到另一个函数中。因此,一个C程序中可能会有很多的函数。为了方便调用和区分这些函数,我们需要为每一个函数都起一个唯一的名称,函数的命名必须按照标识符命名规则。利用函数名就可以调用到对应的函数。

 

  首先来看main()函数。

二、函数的定义

31.    int numCards;  32.    int cards[52],playerPoints[2],dealerPoints[2],total[2];  33.    char ans;

美洲杯赌球,1.任何一个函数在使用之前都必须进行定义

定义函数的目的就是为了写清楚你这个函数是干啥用的,里面包含了哪些代码。函数的定义格式如下:

1 返回值类型  函数名(形式参数列表)  2 {  3     函数体  4 }

 

 

2.举例

比如定义一个函数用来计算两个整数的和。那么可以写成下面这样:

 1 #include <stdio.h>   2    3 int sum(int a, int b)   4 {   5     int c = a   b;   6     return c;   7 }   8    9 int main()  10 {  11     int d = sum(10, 11);  12       13     printf("d is %d", d);  14     return 0;  15 }
  • 分别在第3行、第9行定义了sum函数、main函数,其中sum函数的作用是计算两个整数的和。
  • 函数定义好后,并不会马上执行函数内部的代码,要有人调用它才会执行内部的代码。就好像你的手机虽然有打电话的功能,但是只有按了拨号键,才会执行打电话的功能。
  • 程序运行时就会先调用main函数,按顺序执行第11~14行代码,因为main函数是程序的入口
  • 第11行的sum(10, 11)是调用sum函数,sum函数被调用了,就会分配存储空间给形式参数列表中的所有参数,也就是第3行中的变量a和变量b,它们都是“形式参数”
  • 第11行中的10、11称为“实际参数”,它们将分别赋值给变量a、变量b,也就是相当于

    1 int a = 10; 2 int b = 11;

  • 既然调用了sum函数,就会按顺序执行sum函数中的代码,也就是第5~6行代码。

  • 第5行将a b的值21赋值给了变量c,第6行使用return关键字将变量c返回给了函数调用者,也是说,第11行sum(10, 11)的值是21。那么变量d的值就是21。
  • 第13行的输出结果为:

    d is 21

  • 第3~7行中的变量a、b、c都只有在调用sum函数时,才会分配存储空间,当sum函数执行完毕后,变量a、b、c就会被释放存储空间。因此,它们的作用域仅限于sum函数内部。

  • 第3行sum左边的int称为“返回值类型”,第6行return关键字后面跟着的数值称为“返回值”,因此第6行的变量c就是返回值,返回值的数据类型应该跟“返回值类型”保持一致。

 

  31.行和32.行是这个程序所处理的基本数据对象,相比之下,33.行定义的变量ans则比蚂蚁(ant)还渺小,比鸡肋还无聊,后面会谈到原因。
  main()函数主要说了一句话(另一句是老生常谈的return 0;),是一句do-while语句:

三、形式参数和实际参数

 

1.基本概念

1> 形式参数:在定义函数时,函数名后面的小括号()中定义的变量称为形式参数,简称形参

2> 实际参数:在调用函数时传入的值称为实际参数,简称实参

 

35.    do   36.    {           /*……*/  62.       ans = getAns("nPlay again(Y/N)?");    63.    }  64.    while(ans=='Y');

2.调用函数时传递的实参个数 必须和 函数的形参个数必须保持一致

 1 int sum(int a, int b, int c)   2 {   3     return a   b   c;   4 }   5    6 int main()   7 {   8     sum(10, 9, 7);   9     return 0;  10 }

第1行中sum函数中有3个形参,因此在第8行调用sum函数时,需要传入3个实参

 

 

3.当使用基本数据类型(char、int、float等)作为实参时,实参和形参之间只是值传递,修改形参的值并不影响到实参

 1 #include <stdio.h>   2    3 int test(char a)   4 {   5     a = 10;   6        7     return 0;   8 }   9   10 int main()  11 {  12     char b = 5;  13       14     test(b);  15       16     printf("b的值是%d", b);  17       18     return 0;  19 }
  • 在第3行定义了test函数,只有一个形参a
  • 在第14行调用了test函数,接着就会分配内存给变量a。这里将变量b当做实参,那么变量b的值将传递给变量a。这个时候,内存中大致如下图所示:

美洲杯赌球 4

(其实在内存中存储的是二进制数据,这里我写成10进制是为了直观性)

  • 执行完第5行代码后,变量a的值变成了10,但是变量b的值依然是5

美洲杯赌球 5

  • 第16行代码的输出结果是:

    b的值是5

因此,在函数内部修改了形参的值,并不会影响到外面的实参。

 

  它想实现的意图是在一局游戏结束后,由用户选择结束程序还是继续下一轮游戏。但其实说这句话其实根本用不着那个ans变量,代码可以更简洁地写为:

4.函数可以没有形参

定义一个函数时是可以没有形参的,比如下面的函数

 1 #include <stdio.h>   2    3 int test()   4 {   5     printf("调用了test函数");   6     return 0;   7 }   8    9 int main()  10 {  11     test();  12     return 0;  13 }
  • 在第3行定义了test函数,可以发现,它的形参列表是空的,也就是没有形参
  • 那么在第11行调用test函数时,就不用传递任何实参
  • 其实,第9行定义的main函数也是没有形参的

 

 

四、返回值类型

TAG标签:
版权声明:本文由美洲杯赌球发布于计算机教程,转载请注明出处:劣质代码评析&mdash;&mdash;《写给大家看的C语言书