C语言程序设计现代方法 第十章 程序结构 编程题答案

练习10-1
修改 10.2节的栈示例使它存储字符而不是整数。接下来,增加 main函数,用来要求用户输入一串圆 括号或花括号,然后指出它们之间的嵌套是否正确: Enter parenteses and/or braces: ((){}{()}) Parenteses/braces are nested properly 提示:读入左圆括号或左花括号时,把它们像字符一样压入栈中。当读入右圆括号或右花括号时, 把栈顶的项弹出,并且检查弹出项是否是匹配的圆括号或花括号。(如果不是,那么圆括号或花括号 嵌套不正确。)当程序读入换行符时,检查栈是否为空。如果为空,那么圆括号或花括号匹配;如果 栈不为空(或者如果曾经调用过 stack_underflow 函数),那么圆括号或花括号不匹配。如果调用 stack_overflow 函数,程序显示信息 Stack overflow,并且立刻终止。

main.c

#include <stdio.h>
#include "stack.h"

int main(void) {
    int ch;

    while ((ch = getchar()) != '\n' && ch != EOF) {
        if (ch == '{' || ch == '(')
            push(ch);
        else if (ch == '}' && pop() != '{' ||
                 ch == ')' && pop() != '(') {
            printf("括号大括号嵌套错误!\n");
            return 1;
        }
    }

    if (!is_empty()) {
        printf("括号大括号嵌套错误!\n");
        return 1;
    }

    printf("括号大括号正确嵌套。\n");
    return 0;
}

stack.h

#ifndef STACK_H
#define STACK_H

#include <stdbool.h>

void make_empty(void);
void push(int v);
int pop(void);

bool is_empty(void);
bool is_full(void);

#endif

stack.c

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

#define STACK_SIZE 100

char contents[STACK_SIZE];
int top = 0;

void stack_overflow() {
    printf("堆栈溢出!\n");
    exit(EXIT_FAILURE);
}

void stack_underflow() {
    printf("括号大括号嵌套错误!\n");
    exit(EXIT_FAILURE);
}

void make_empty(void) {
    top = 0;
}

bool is_empty(void) {
    return top == 0;
}

bool is_full(void) {
    return top == STACK_SIZE;
}

void push(char i) {
    if (is_full())
        stack_overflow();
    else
        contents[top++] = i;
}

int pop(void) {
    if (is_empty())
        stack_underflow();
    else
        return contents [--top];
}

练习10-2
修改 10.5 节的 poker.c 程序,把数组 num_in_rank 和数组 num_in_suit 移到 main 函数中。main 函 数将把这两个数组作为实际参数传递给 read_cards 函数和 analyze_hand 函数。

main.c

#include "card.h"


int main(void) {
    int num_in_rank[RANK_MAX];
    int num_in_suit[SUIT_MAX];

    for (;;) {
        read_cards(num_in_rank, num_in_suit);
        analyze_hand(num_in_rank, num_in_suit);
        print_result();
    }
}

card.h

#ifndef C_CARD_H
#define C_CARD_H

#define RANK_MAX 13
#define SUIT_MAX 4
#define CARD_NUM 5


void read_cards(int num_in_rank[], int num_in_suit[]);
void analyze_hand(int num_in_rank[], int num_in_suit[]);
void print_result(void);

#endif //C_CARD_H

card.c

#include "card.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

static bool straight;
static bool flush;
static bool four;
static bool three;
static int pairs;

void read_cards(int num_in_rank[], int num_in_suit[]) {
    bool hand[RANK_MAX][SUIT_MAX] = {false};
    int rank, suit;
    int i;

    for (i = 0; i < SUIT_MAX; ++i) {
        num_in_rank[i] = 0;
        num_in_suit[i] = 0;
    }

    while (i < RANK_MAX)
        num_in_rank[i++] = 0;

    i = 0;
    while (i < CARD_NUM) {
        printf("输入第%d张牌:", i + 1);

        switch (getchar()) {
            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;
            case '0':           exit(EXIT_FAILURE);
            default:
                printf("坏牌,请重新输入。\n");
                while (getchar() != '\n')
                    ;
                continue;
        }

        switch (getchar()) {
            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:
                printf("坏牌,请重新输入。\n");
                while (getchar() != '\n')
                    ;
                continue;
        }

        if (getchar() != '\n') {
            while (getchar() != '\n')
                ;
            printf("坏牌,请重新输入。\n");
            continue;
        }

        if (hand[rank][suit]) {
            printf("牌已存在,请重新输入。\n");
            continue;
        }

        num_in_rank[rank] += 1;
        num_in_suit[suit] += 1;
        hand[rank][suit] = true;
        i += 1;
    }
}

void analyze_hand(int num_in_rank[], int num_in_suit[]) {
    straight = false;
    flush = false;
    four = false;
    three = false;
    pairs = 0;

    int i;

    for (i = 0; i < SUIT_MAX; ++i)
        if (num_in_suit[i] == CARD_NUM) {
            flush = true;
            break;
        }

    int n = 0;

    for (i = 0; i < RANK_MAX; ++i) {
        switch (num_in_rank[i]) {
            case 4:
                four = true;
                return;
            case 3:
                three = true;
                if (pairs == 1)
                    return;
                break;
            case 2:
                pairs += 1;
                if (pairs == 2)
                    return;
                break;
            case 1:
                n += 1;
                if (n == CARD_NUM) {
                    straight = true;
                    return;
                }
                break;
            default:
                if (n != 0)
                    n = 0;
        }
    }
}

void print_result(void) {
    if (straight && flush)      printf("同花顺\n");
    else if (four)              printf("四张\n");
    else if (three && pairs)    printf("葫芦\n");
    else if (flush)             printf("同花\n");
    else if (straight)          printf("顺子\n");
    else if (three)             printf("三张\n");
    else if (pairs == 2)        printf("两对\n");
    else if (pairs)             printf("对于\n");
    else                        printf("其他牌\n");
}

练习10-3
把数组 num_in_rank、num_in_suit 和 card_exists 从 10.5 节的 poker.c 程序中去掉。程序改用 5×2 的数组来存储牌。数组的每一行表示一张牌。例如,如果数组名为 hand,则 hand[0][0]存储第一 张牌的点数,hand[0][1]存储第一张牌的花色。

main.c

#include "card.h"

int main(void) {
    for (;;) {
        read_cards();
        analyze_hand();
        print_result();
    }
}

card.h

#ifndef C_CARD_H
#define C_CARD_H

#define RANK_MAX 13
#define SUIT_MAX 4
#define CARD_NUM 5


void read_cards(void);

void analyze_hand(void);

void print_result(void);

#endif //C_CARD_H

card.c

#include "card.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>


static bool straight;
static bool flush;
static bool four;
static bool three;
static int pairs;
static int hand[CARD_NUM][2];


void read_cards(void) {
    int i;
    int j;

    for (i = 0; i < CARD_NUM; ++i) {
        hand[i][0] = 0;
        hand[i][1] = 0;
    }

    i = 0;

    while (i < CARD_NUM) {
        printf("输入第%d张牌:", i + 1);

        switch (getchar()) {
            case '2':           hand[i][0] = 0; break;
            case '3':           hand[i][0] = 1; break;
            case '4':           hand[i][0] = 2; break;
            case '5':           hand[i][0] = 3; break;
            case '6':           hand[i][0] = 4; break;
            case '7':           hand[i][0] = 5; break;
            case '8':           hand[i][0] = 6; break;
            case '9':           hand[i][0] = 7; break;
            case 't': case 'T': hand[i][0] = 8; break;
            case 'j': case 'J': hand[i][0] = 9; break;
            case 'q': case 'Q': hand[i][0] = 10; break;
            case 'k': case 'K': hand[i][0] = 11; break;
            case 'a': case 'A': hand[i][0] = 12; break;
            case '0':           exit(EXIT_FAILURE);
            default:
                printf("坏牌,请重新输入。\n");
                while (getchar() != '\n')
                    ;
                continue;
        }

        switch (getchar()) {
            case 'c': case 'C': hand[i][1] = 0; break;
            case 'd': case 'D': hand[i][1] = 1; break;
            case 'h': case 'H': hand[i][1] = 2; break;
            case 's': case 'S': hand[i][1] = 3; break;
            default:
                printf("坏牌,请重新输入。\n");
                while (getchar() != '\n')
                    ;
                continue;
        }

        if (getchar() != '\n') {
            while (getchar() != '\n')
                ;
            printf("坏牌,请重新输入。\n");
            continue;
        }

        for (j = 0; j < i; ++j)
            if (hand[j][0] == hand[i][0] && hand[j][1] == hand[i][1]) {
                printf("牌已经存在,请重新输入。\n");
                goto end; // 跳过自增i
            }

        i += 1;

        end:; // 标号后面需要有语句
    }
}



void analyze_hand(void) {
    straight = false;
    flush = true;
    four = false;
    three = false;
    pairs = 0;

    int num_in_rank[RANK_MAX] = {0};
    int i;


    for (i = 1; i < CARD_NUM; ++i) {
        if (hand[i][1] != hand[i - 1][1])
            flush = false;
        num_in_rank[hand[i][0]] += 1;
    }

    num_in_rank[hand[0][0]] += 1;

    int n = 0; // 统计连续数量

    for (i = 0; i < RANK_MAX; ++i) {
        switch (num_in_rank[i]) {
            case 4:
                four = true;
                return;
            case 3:
                three = true;
                if (pairs == 1)
                    return;
                break;
            case 2:
                pairs += 1;
                if (pairs == 2)
                    return;
                break;
            case 1:
                n += 1;
                if (n == CARD_NUM) {
                    straight = true;
                    return;
                }
                break;
            default:
                if (n != 0)
                    n = 0;
        }
    }
}


void print_result(void) {
    if (straight && flush)      puts("同花顺");
    else if (four)              puts("四张");
    else if (three && pairs)    puts("葫芦");
    else if (flush)             puts("同花");
    else if (straight)          puts("顺子");
    else if (three)             puts("三张");
    else if (pairs == 2)        puts("两对");
    else if (pairs)             puts("对于");
    else                        puts("其他牌");
}

练习10-4
修改 10.5 节的 poker.c 程序,使其能识别牌的另一种类别——“同花大顺”(同花色的 A、K、Q、J 和 10)。同花大顺的级别高于其他所有的类别。

main.c

#include "card.h"


int main(void) {

    for (;;) {
        read_cards();
        analyze_hand();
        print_result();
    }
}

card.h

#ifndef C_CARD_H
#define C_CARD_H

#define RANK_MAX 13
#define SUIT_MAX 4
#define CARD_NUM 5


void read_cards(void);

void analyze_hand(void);

void print_result(void);

#endif //C_CARD_H

card.c

#ifndef C_CARD_H
#define C_CARD_H

#define RANK_MAX 13
#define SUIT_MAX 4
#define CARD_NUM 5


void read_cards(void);

void analyze_hand(void);

void print_result(void);

#endif //C_CARD_H

练习10-5
修改 10.5 节的 poker.c 程序,使其能识别“小 A 顺”(即 A、2、3、4 和 5)。

main.c

#include "card.h"


int main(void) {

    for (;;) {
        read_cards();
        analyze_hand();
        print_result();
    }
}

card.h

#ifndef C_CARD_H
#define C_CARD_H


#define RANK_MAX 13
#define SUIT_MAX 4
#define CARD_NUM 5


void read_cards(void);

void analyze_hand(void);

void print_result(void);

#endif //C_CARD_H

card.c

#include "card.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>


static int num_in_rank[RANK_MAX];
static int num_in_suit[SUIT_MAX];
static bool royal_flush;
static bool wheel_straight;
static bool straight;
static bool flush;
static bool four;
static bool three;
static int pairs;



void read_cards(void) {
    bool hand[RANK_MAX][SUIT_MAX] = {false};
    int rank, suit;
    int i;

    for (i = 0; i < SUIT_MAX; ++i) {
        num_in_rank[i] = 0;
        num_in_suit[i] = 0;
    }

    while (i < RANK_MAX)
        num_in_rank[i++] = 0;

    i = 0;

    while (i < CARD_NUM) {
        printf("输入第%d张牌:", i + 1);

        switch (getchar()) {
            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;
            case '0':           exit(EXIT_FAILURE);
            default:
                puts("坏牌,请重新输入。");
            while (getchar() != '\n')
                ;
            continue;
        }

        switch (getchar()) {
            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:
                printf("坏牌,请重新输入。\n");
            while (getchar() != '\n')
                ;
            continue;
        }

        if (getchar() != '\n') {
            while (getchar() != '\n')
                ;
            printf("坏牌,请重新输入。\n");
            continue;
        }

        if (hand[rank][suit]) {
            printf("牌已存在,请重新输入。\n");
            continue;
        }

        num_in_rank[rank] += 1;
        num_in_suit[suit] += 1;
        hand[rank][suit] = true;
        i += 1;
    }
}



void analyze_hand(void) {
    royal_flush = false;
    wheel_straight = false;
    straight = false;
    flush = false;
    four = false;
    three = false;
    pairs = 0;

    int i;

    for (i = 0; i < SUIT_MAX; ++i)
        if (num_in_suit[i] == CARD_NUM) {
            flush = true;
            break;
        }

    if (num_in_rank[0] && num_in_rank[1] && num_in_rank[2] && num_in_rank[3] && num_in_rank[12]) {
        wheel_straight = true;
        return;
    }
    if (num_in_rank[8] && num_in_rank[9] && num_in_rank[10] && num_in_rank[11] && num_in_rank[12]) {
        royal_flush = true;
        return;
    }

    int n = 0;

    for (i = 0; i < RANK_MAX; ++i) {
        switch (num_in_rank[i]) {
            case 4: four = true; return;
            case 3: three = true;
                if (pairs == 1)
                    return;
                break;
            case 2: pairs += 1;
                if (pairs == 2)
                    return;
                break;
            case 1: n += 1;
                if (n == CARD_NUM) {
                    straight = true;
                    return;
                }
                break;
            default:
                n = 0;
        }
    }
}


void print_result(void) {
    if (royal_flush)            printf("皇家同花顺\n");
    else if (wheel_straight)    printf("小A顺\n");
    else if (straight && flush) printf("同花顺\n");
    else if (four)              printf("四张\n");
    else if (three && pairs)    printf("葫芦\n");
    else if (flush)             printf("同花\n");
    else if (straight)          printf("顺子\n");
    else if (three)             printf("三张\n");
    else if (pairs == 2)        printf("两对\n");
    else if (pairs)             printf("对于\n");
    else                        printf("其他牌\n");
}

练习10-6
有些计算器(尤其是惠普的计算器)使用逆波兰表示法(Reverse Polish Notation,RPN)来书写数学 表达式。在这一表示法中,运算符放置在操作数的后面而不是放在操作数中间。例如,在逆波兰表 示法中 1+2 将表示为 1 2 +,而 1+23 将表示为 1 2 3 * +。逆波兰表达式可以很方便地用栈求值。算 法从左向右读取运算符和操作数,并执行下列步骤。
(1) 当遇到操作数时,将其压入栈中。
(2) 当遇到运算符时,从栈中弹出它的操作数,执行运算并把结果压入栈中。
编写程序对逆波兰表达式求值。操作数都是个位的整数,运算符为+、-、
、/和=。遇到运算符= 时,将显示栈顶项,随后清空栈并提示用户计算新的表达式。这一过程持续进行,直到用户输入一 个既不是运算符也不是操作数的字符为止:
Enter an RPN expression: 1 2 3 * + =
Value of expression: 7
Enter an RPN expression: 5 8 * 4 9 - / =
Value of expression: -8
Enter an RPN expression: q
如果栈出现上溢,程序将显示消息 Expression is too complex 并终止。如果栈出现下溢(例如遇 到表达式 1 2 + +),程序将显示消息 Not enough operands in expression 并终止。提示:把 10.2 节的栈代码整合到你的程序中。使用 scanf(" %c", &ch)读取运算符和操作数。

main.c

#include <stdio.h>
#include <ctype.h>
#include "stack.h"


int main(void) {
    int pop2;
    char c;

    printf("输入 RPN 表达式:");

    for (;;) {
        scanf(" %c", &c);

        switch (c) {
            case ' ':               break;
            case '+':               push(pop() + pop()); break;
            case '*':               push(pop() * pop()); break;
            case '-': pop2 = pop(); push(pop() - pop2); break;
            case '/': pop2 = pop(); push(pop() / pop2); break;
            case '=': printf("结果是:%d\n输入 RPN 表达式:", pop()); break;
            case 'q':               return 0;
            default:  if (isdigit(c)) push(c - '0');
        }
    }
}

stack.h

#ifndef STACK_H
#define STACK_H

#include <stdbool.h>

void make_empty(void);
void push(int v);
int pop(void);

bool is_empty(void);
bool is_full(void);

#endif

stack.c

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

#define STACK_SIZE 100

int contents[STACK_SIZE];
int top = 0;

void stack_overflow() {
    printf("表达太复杂!\n");
    exit(EXIT_FAILURE);
}

void stack_underflow() {
    printf("表达式中的操作数不足!\n");
    exit(EXIT_FAILURE);
}

void make_empty(void) {
    top = 0;
}

bool is_empty(void) {
    return top == 0;
}

bool is_full(void) {
    return top == STACK_SIZE;
}

void push(int i) {
    if (is_full())
        stack_overflow();
    else
        contents[top++] = i;
}

int pop(void) {
    if (is_empty())
        stack_underflow();
    else
        return contents [--top];
}

练习10-7
编写程序,提示用户输入一个数并显示该数,使用字符模拟七段显示器的效果: Enter a number: 491-9014 非数字的字符都将被忽略。在程序中用一个名为 MAX_DIGITS 的宏来控制数的最大位数,MAX_DIGITS 的值为 10。如果数中包含的数位大于这个数,多出来的数位将被忽略。提示:使用两个外部数 组,一个是 segments 数组(见第 8 章的练习题 6),用于存储表示数字和段之间对应关系的数据; 另一个是 digits 数组,这是一个 3行(因为显示出来的每个数字高度都是 3个字符)、MAX_DIGITS× 4 列(数字的宽度是 3 个字符,但为了可读性需要在数字之间增加一个空格)的字符数组。编写 4 个 函数:main、clear_digits_array、process_digit 和 print_digits_array。下面是后 3 个函数 的原型: void clear_digits_array(void); void process_digit(int digit, int position); void print_digits_array(void); clear_digits_array函数在digits数组的所有元素中存储空白字符。process_digit函数把digit 的七段表示存储到 digits 数组的指定位置(位置为 0~MAX_DIGITS1)。print_digits_array 函数 分行显示 digits 数组的每一行,产生的输出如示例图所示。

#include <stdio.h>
#include <ctype.h>

#include "../13/my_util.h"


#define MAX_DIGITS 10
#define MAX_WIDTH 4


const char char_digit[10][3][3] =
{
    {' ', '_', ' ',
     '|', ' ', '|',
     '|', '_', '|'},
    {' ', ' ', ' ',
     ' ', ' ', '|',
     ' ', ' ', '|'},
    {' ', '_', ' ',
     ' ', '_', '|',
     '|', '_', ' '},
    {' ', '_', ' ',
     ' ', '_', '|',
     ' ', '_', '|'},
    {' ', ' ', ' ',
     '|', '_', '|',
     ' ', ' ', '|'},
    {' ', '_', ' ',
     '|', '_', ' ',
     ' ', '_', '|'},
    {' ', '_', ' ',
     '|', '_', ' ',
     '|', '_', '|'},
    {' ', '_', ' ',
     ' ', ' ', '|',
     ' ', ' ', '|'},
    {' ', '_', ' ',
     '|', '_', '|',
     '|', '_', '|'},
    {' ', '_', ' ',
     '|', '_', '|',
     ' ', '_', '|'},
};

char digits[3][MAX_DIGITS * MAX_WIDTH];

void clear_digits_array(void);
void print_digits_array(void);
void process_digit(int digit, int position);


int main(void) {
    int ch;

    clear_digits_array();
    printf("输入数字:");

    for (int i = 0; i < MAX_DIGITS; ++i) {
        while (!isdigit(ch = getchar()))
            if (ch == '\n')
                goto end; // 跳两层循环

        process_digit(ch - '0', i);
    }

    end:
    print_digits_array();
    return 0;
}


void process_digit(int digit, int position) {
    int i, j;
    for (i = 0; i < 3; ++i)
        for (j = 0; j < 3; ++j)
            digits[i][position * MAX_WIDTH + j] = char_digit[digit][i][j];
}


void clear_digits_array(void) {
    for (int j = 3 * MAX_DIGITS * MAX_WIDTH - 1; j >= 0; --j)
        digits[0][j] = ' ';
}


void print_digits_array(void) {
    int i, j;

    for (i = 0; i < 3; ++i) {
        for (j = 0; j < MAX_DIGITS * MAX_WIDTH; ++j)
            putchar(digits[i][j]);
        endl;
    }
}
  • 16
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值