• 结构

局部变量:用简单的描述一下作用域和生存期:

作用域:限定某个名字的可用性的代码范围就是该名字的作用域

生存期:变量值存在的时间

块:一个花括号{}就是一个块。

通常来说,变量的作用域和生存期都是在一个块内。

  1. 静态局部变量

在局部变量中放置单词 static 可以使变量具有静态存储期限而不再是自动存储期限。

因为具有静态存储期限的变量拥有永久的存储单元,所以在整个程序的执行期间都会保留变量的值。比如:

void func(){
int static n; // static locol variable
}
在函数 func 返回时,变量 n 的值不会丢失。

静态局部变量虽然生存期是整个程序,但是作用域尽在其所定义的块内。也就是说,上例中函数 func 返回后,func 内的 n 就不再可用。

2.全局变量

文件作用域。全局变量的作用域:从变量被声明的点开始一直到所在文件的末尾。外部变量声明之后的函数都可以访问(并修改)它
在大多数情况下,对于函数而言,传参比共享变量更好

不建议使用全局变量。

从头到尾去写一个 c 程序。我们这里给出比较好的编排顺序:

  1. include指令

  2. define指令

  3. 类型定义

  4. 全局变量声明

  5. 函数原型

  6. main 函数定义

  7. 其他函数定义

    /*
    * 程序难点思路:
    * 1)为了判定手中的牌是否重复,我们需要一个布尔类型数组存储整副牌,初始化整个数组为 false。如果一张牌已经在我们手上,那么我们将数组对应的元素置为 true
    * 2)用两个分别数组来存储每个点数和花色的个数,这样方便我们后面判断牌的类型
    * 3)8 种牌的类型,我们可拆成 同花,顺子,4张,3张,对子(值为 0,1,2)这五种基础类型的组合。
    *
    * 程序结构:
    * 通过上面的分析,我们发现:这个程序需要 3 个数组和 5 个变量,如果都作为函数参数传参,显得有些笨。
    * 而且,前面我们说过,函数只能返回一个值,那如果要将函数分离, 5 种基础类型就得放进数组;或者使用指针,而指针我们没有学习,而且指针还是逃不开传参
    * 这样一分析,貌似使用全局变量是最好的做法了。对于初学者来说,这样可能确实是最好的。
    * 但是,使用大量的全局变量是很不好的习惯,我不能让自己去写这样的代码。我认为:宁可这道题不做,也不能有坏的代码风格去写!
    * 后面我们会学习自定义类型:结构体,它可能是这种问题最好的解决方法。
    *
    * 下面是这个问题的 4 种解决方法:
    * 1)应用全局变量
    * 2)应用指针作为函数参数
    * 3)将判断卡牌类型的函数与打印函数合并
    * 4)使用结构体
    *
    * 在这里,我坚持使用结构体来解决这类问题。全局变量大家只要知道概念即可,对于这道题来说,比起方法,可能设计程序的模块化思路更值得学习。
    * 即使使用结构体,程序的主要逻辑也不会变。如果你非要用全局变量写,那你可以改写一下。
    */

    `#include<stdio.h>

    include<stdbool.h>

    define RANK 13

    define SUIT 4

    define CARD 5

    typedef struct CardType {
    bool flush; //同花
    bool straight; //顺子
    bool four; //四张
    bool three; //三张
    int pair; // 对子
    // 0 表示不是 1 表示 1个对子 2 表示两个对子
    bool cardInHand[SUIT][RANK]; // 判断此牌是否已在手中
    int numRank[RANK]; // 每个点数的个数
    int numSuit[SUIT]; // 每个花色的个数
    }CardType;

    void initCardType(CardType* card); // 初始化
    void readCard(CardType* card); // 读取输入
    void analyseCard(CardType* card); // 分析手牌
    void printResult(CardType* card); //打印结果

    int main(void) {

     CardType card;
     
     for (; ;) {
     	initCardType(&card);
     	readCard(&card);
     	analyseCard(&card);
     	printResult(&card);
     }
    
     return 0;
    

    }

    void initCardType(CardType* card) {

     card->flush = false;
     card->straight = false;
     card->four = false;
     card->three = false;
     card->pair = 0;
    
     int i, j;
    
     for (i = 0; i < SUIT; i++) {
     	card->numSuit[i] = 0;
     	for (j = 0; j < RANK; j++) {
     		card->cardInHand[i][j] = false;
     	}
     }
    
     for (i = 0; i < RANK; i++) {
     	card->numRank[i] = 0;
     }
    

    }

    void readCard(CardType* card) {

     int card_read = CARD, rank, suit;
     bool bad_card;
     char ch;
    
     while (card_read) {
     	
     	bad_card = false; // 不要忘记重置坏牌的标记
    
     	printf("Enter a card : ");
     	
     	// 判断点数
     	ch = getchar();
     	switch (ch) {
     		case '0':			exit(0); break;
     		case '2':		   rank = 0; break;
     		case '3':		   rank = 1; break;
     		case '4':		   rank = 2; break;
     		case '5':		   rank = 3; break;
     		case '6':		   rank = 4; break;
     		case '7':		   rank = 5; break;
     		case '8':		   rank = 6; break;
     		case '9':		   rank = 7; break;
     		case 't':case 'T': rank = 8; break;
     		case 'j':case 'J': rank = 9; break;
     		case 'q':case 'Q': rank = 10; break;
     		case 'k':case 'K': rank = 11; break;
     		case 'a':case 'A': rank = 12; break;
     		default:bad_card = true; break;
     	}
    
     	ch = getchar();
     	switch (ch) {
     		case 'c': case 'C': suit = 0; break;
     		case 'd': case 'D': suit = 1; break;
     		case 'h': case 'H': suit = 2; break;
     		case 's': case 'S': suit = 3; break;
     		default: bad_card = true; break;
     	}
     	
     	// 检测输入是否多于两个字符
     	while ((ch = getchar()) != '\n') {
     		if (ch != ' ')
     			bad_card = true;
     	}
    
     	if (bad_card)
     		printf("Bad card; ignored.\n");
     	else if (card->cardInHand[suit][rank])
     		printf("Duplicated card; ignored.\n");
     	else {
     		++card->numRank[rank];
     		++card->numSuit[suit];
     		card->cardInHand[suit][rank] = true;
     		card_read--;
     	}
     }
    

    }

    void analyseCard(CardType* card) {

     int i, count;
    
     // 同花是五张牌相同花色
     for (i = 0; i < SUIT; i++) {
     	if (card->numSuit[i] == 5)
     		card->flush = true;
     }
    
     // 顺子是五张连续的牌,中间不能隔断
     
     i = 0;
     // 找到数组种第一张存在的牌
     while (card->numRank[i] == 0)
     	i++;
     count = 0;
     for (; i < RANK && card->numRank[i] != 0; i++) {
     	count++;
     }
     // 顺子必须是五张
     if (count == CARD) {
     	card->straight = true;
     	return; // 顺子肯定不是对子
     }
    
     for (i = 0; i < RANK; i++) {
     	if (card->numRank[i] == 4)
     		card->four = true;
     	if (card->numRank[i] == 3)
     		card->three = true;
     	if (card->numRank[i] == 2)
     		++card->pair;
     }
    

    }

    void printResult(CardType* card) {

     if (card->flush && card->straight)
     	printf("Stright flush\n");
     else if (card->four)
     	printf("Four of a kind\n");
     else if (card->three && card->pair == 1)
     	printf("Full house\n");
     else if (card->flush)
     	printf("flush\n");
     else if (card->straight)
     	printf("straight\n");
     else if (card->three)
     	printf("Three of a kind\n");
     else if (card->pair == 2)
     	printf("Two pairs\n");
     else if (card->pair == 1)
     	printf("pair\n");
     else
     	printf("High card\n");
     
     printf("\n\n");
    

    }`