目录
第四章(表达式),第五章(语句),第六章(数组)思维导图
解答:
题目一 :扔骰子
编写程序模拟掷骰子的游戏(两个骰子)。每局游戏的规则如下:
第一次掷的时候,如 果点数之和为 7 或 11 则获胜;如果点数之和为2、3或12则落败;其他情况下的点数之和称为“目标”,游戏继续。在后续的投掷中,如果玩家再次掷出“目标”点数则获胜,掷出7则落败,其他情况都忽略,游戏继续进行。
每局游戏结束时,程序询问用户是否再玩一次,如果用 户输入的回答不是 y 或 Y ,程序会显示胜败的次数然后终止。(拓展题,不要求每个同学回答)
You rolled: 8
Your point is 8
You rolled: 3
You rolled: 10
You rolled: 8
You win!
Play again? y
You rolled: 6
Your point is 6
You rolled: 5
You rolled: 12
You rolled: 3
You rolled: 7
You lose!
Play again? y
You rolled: 11
You win!
Play again? n
Wins: 2 Losses: 1
解答01_有BUG:
BUG:while ((again = getchar()) == 'y' || (again = getchar()) == 'Y');
改正:scanf(" %c",&again);//不能忽略空格,否则会造成交互错误
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
int roll_dices();
int play_game(int a,int point,int count);
int main(void) {
srand(time(NULL));
char again;
int wins = 0; int losses = 0; int dices=0;
do {
//一局游戏的内部循环
int count=0 ; int point;
int com_game = 0;
do {
point = dices;
dices = roll_dices();
printf("You rolled:%d\n", dices);
com_game = play_game(dices, point, count);
switch (com_game) {
case 0:
count++;
break;
case 1:
printf("You win!\n");
wins++;
break;
case 2:
printf("You lose!\n");
losses++;
break;
}
} while (com_game==0);
printf("Play again?\n");
} while ((again = getchar()) == 'y' || (again = getchar()) == 'Y');
printf("Wins: %d Losses: %d\n",wins,losses);
return 0;
}
int roll_dices() {
int random_num = 2 + rand() % 10;
return random_num;
}
int play_game(int a, int point, int count) {
if(count==0){
if (a == 7 || a == 11) {
return 1;
}
else if (a == 2 || a == 3 || a == 12) {
return 2;
}
else {
printf("Your point is %d\n", a);
return 0;
}
}
else if(count!=0){
if (a == point) {
return 1;
}
else if (a == 7) {
return 2;
}
else {
return 0;
}
}
}
解答02:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
int roll_dices();
int play_game(int a,int point,int count);
int main(void) {
srand(time(NULL));
char again='y';
int wins = 0; int losses = 0; int dices=0;
do {
//一局游戏的内部循环
int count=0 ; int point;
int com_game = 0;
do {
point = dices;
dices = roll_dices();
printf("You rolled:%d\n", dices);
com_game = play_game(dices, point, count);
switch (com_game) {
case 0:
count++;
break;
case 1:
printf("You win!\n");
wins++;
break;
case 2:
printf("You lose!\n");
losses++;
break;
}
} while (com_game==0);
printf("Play again?\n");
scanf(" %c",&again);
} while (again=='y'||again=='Y');//(again = getchar()) == 'y' || (again = getchar()) == 'Y'//使用了两次GETCHAR,可能导致逻辑错误或影响交互体验
printf("Wins: %d Losses: %d\n",wins,losses);
return 0;
}
int roll_dices() {
int random_num = 2 + rand() % 10;
return random_num;
}
int play_game(int a, int point, int count) {
if(count==0){
switch (a) {
case 7:case 11:
return 1;
case 2:case 3:case 12:
return 2;
default:
printf("Your point is %d\n", a);
return 0;
}
}
else if(count!=0){
if (a == point) {
return 1;
}
else if (a == 7) {
return 2;
}
else {
return 0;
}
}
}
答案:
do {
play_game() ? wins++ : losses++; //play_game返回一个布尔值,条件运算符
// 询问玩家是否继续
printf("\nPlay agiain? ");
// 读取第一个非空白字符
scanf(" %c", &again);
// 跳过这一行剩余字符 //可能是YES跳过ES!!!!
while (getchar() != '\n')
;
} while (again == 'Y' || again == 'y');#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdbool.h> #include <stdlib.h> #include <time.h> bool play_game(void); int roll_dice(void); int main(void) { int wins = 0, losses = 0; char again; do { play_game() ? wins++ : losses++; // 询问玩家是否继续 printf("\nPlay agiain? "); // 读取第一个非空白字符 scanf(" %c", &again); // 跳过这一行剩余字符 while (getchar() != '\n') ; } while (again == 'Y' || again == 'y'); printf("\nWins: %d Losses: %d\n", wins, losses); return 0; } bool play_game(void) { // 设置随机种子 srand(time(NULL)); int point = roll_dice(); if (point == 7 || point == 11) { printf("You win!\n"); return true; } if (point == 2 || point == 3 || point == 12) { printf("You lose!\n"); return false; } printf("Your point is %d\n", point); for (;;) { int tally = roll_dice(); if (tally == point) { printf("You win!\n"); return true; } if (tally == 7) { printf("You lose!\n"); return false; } } } int roll_dice() { int a = rand() % 6 + 1; int b = rand() % 6 + 1; printf("You rolled: %d\n", a + b); return a + b; }
题目二 :德州扑克
(拓展题,不要求每个同学都作答) 德州扑克:写一个程序循环读取 5 张手牌 (输入 0 结束程序),然后把手中的牌分为下面某一类:1.同花顺 2.四张 3.葫芦 (3 + 2) 4. 同花 5. 顺子 6.三张 7.两对 8. 一对 9.高牌。
同花顺(Straight Flush): 五张同花色的连续数字牌,如红桃10-J-Q-K-A.
四张(Four of a Kind): 四张相同数字的牌,加一张其他数字的牌,如 A-A-A-A-K
葫芦(Full house): 三张相同数字的牌,加上一对其他数字的牌,如 A-A-A-K-K
同花(Flush): 五张同花色的牌,但不是顺子,如红桃 2-5-7-8-K
顺子(Straight): 由五张连续数字的牌组成 (简单起见,A-2-3-4-5 不是顺子),但不是同花。 如 2-3-4-5-6, 但包含不同花色的牌。
三张(Three of a kind): 由三张相同数字的牌,加两张不同数字的牌组成。如 A-A-A-2-K
两对(Two pair): 由两对加上一张杂牌组成。如 A-A-K-K-2
对子(Pair): 由一对加上三张不同的牌组成。如 A-A-5-6-K
高牌(High card): 无法组成上述任一牌型的杂牌。如 2-5-8-10-Q,且包含多种花色的牌。
程序对话如下:
Enter a card: 2s
Enter a card: 5s
Enter a card: 4s
Enter a card: 3s
Enter a card: 6s
Straight flush
Enter a card: 8c
Enter a card: as
Enter a card: 8c
Duplicate card; ignored.
Enter a card: 7c
Enter a card: ad
Enter a card: 3h
Pair
Enter a card: 6s
Enter a card: d2
Bad card; ignored.
Enter a card: 2d
Enter a card: 9c
Enter a card: 4h
Enter a card: ts
High card
Enter a card: 0
解答/不对的挣扎:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#define SIZE(a) (sizeof(a)/sizeof(a[0]))
int get_end(int same_ranks[],int max_ranks, int min_rank, int same_suits, int len);
int main(void) {
const char rank[] = { '1','2','3','4','5','6','7','8','9','t','j','q','k','a' };
const char suit[] = { 'd','c','h','s' };
int result_rank[5];//记录牌号
int result_suit[5];
bool is_hand[13][4] = { false };
char my_rank, my_suit;
int num = 5;
int i; int j; //for循环参数
for (; ;) {
for (;num!=0;) {
scanf(" %c %c", &my_rank, &my_suit);
if (my_rank == '0') {
exit(0);
}
for (i = 0; i < SIZE(rank); i++)
{
for (j = 0; j < SIZE(suit); j++)
{
if (my_rank == rank[i] && my_suit == suit[j] && num != 0)
{
if (is_hand[i][j] == false)
{
is_hand[i][j] = true;
result_rank[num] = i; //记录牌号0-12
result_suit[num] = j; //0-3
//printf("%d-%d ", i, j);
num--;
}
else if (is_hand[i][j] == true)
{
printf("Duplicate card; ignored.\n");
}
else
{
printf("Bad card; ignored.\n");
}
}
}
}
}
//记录了5组数组再开始下一步
num = 5; //初始化NUM-循环
int same_ranks[4] = { 0 }; //相同牌面数量
int max_ranks= result_rank[0]; //最大牌面
int min_rank = result_rank[0]; //最小牌面
int same_suits = 0; //相同花色——只需要考虑花色全部相同的情况
for (i = 0; i < 5; i++) { //解读五张牌RANK
for (j = 0; j < 5-i; j++) {
if (result_rank[i] == result_rank[j]) {
same_ranks[i]++;
}
}
max_ranks = max_ranks > result_rank[i] ? max_ranks : result_rank[i];
min_rank = min_rank < result_rank[i] ? min_rank : result_rank[i];
}
for (i = 0; i < 5; i++) { //解读五张牌suit
for (j = 0; j < 5 - i; j++) {
if (result_suit[i] == result_suit[j]) {
same_suits++;
}
}
}
//查看结果
switch (get_end(same_ranks, max_ranks, min_rank,same_suits,4)) {
case 1:
printf("同花顺Straight Flush\n");
break;
case 2:
printf("四条Four of a Kind\n");
break;
case 3:
printf("葫芦(Full House)\n");
break;
case 4:
printf("同花Flush\n");
break;
case 5:
printf("顺子Straight\n");
break;
case 6:
printf("三条(Three of a Kind)\n");
break;
case 7:
printf("两对(Two Pair)\n");
break;
case 8:
printf("一对(One Pair)\n");
break;
case 9:
printf("高牌(High Card)\n");
break;
}
//清零数组数据
//is_hand[13][4] = { false };
}
return 0;
}
int get_end(int same_ranks[], int max_ranks, int min_rank, int same_suits, int len) {
if ((max_ranks - min_rank == 4) || same_suits == 4) {
return 1;
}else if ((max_ranks - min_rank == 4) || same_suits != 4) {
return 5;
}
else if ((max_ranks - min_rank != 4) || same_suits == 4) {
return 4;
}
else {
int same_max=same_ranks[0], same_min= same_ranks[0];
int i;
for (i = 1; i < len; i++) {
same_max = same_max > same_ranks[i] ? same_max : same_ranks[i];
same_min = same_min < same_ranks[i] ? same_min : same_ranks[i];
}
switch (same_max - same_min) {
case 4:
return 2; break;
case 2:
return 7; break;
case 1:
return 8; break;
case 0:
return 9; break;
case 3:
for (i = 0; i < len; i++) {
if (same_ranks[i] == 2) {
return 3; break;
}
else if (same_ranks[i] == 1) {
return 6; break;
}
}
break;
}
}
}
/*
4,同花(Flush): //SUIT 相同,
1,同花顺(Straight Flush):任意花色的连续五张牌。 //RANK连续(最大的RANK标号-最小的==4),-suit相同
5,顺子(Straight):连续的五张牌。 //RANK连续(最大的RANK标号-最小的==4) suit不定
2,四条(Four of a Kind):四张同等级的牌。 //RANK 4,1 4100 40 4
3,葫芦(Full House):三张同等级的牌加一对其他等级的牌。 //RANK 3-2 3200 30 3
6,三条(Three of a Kind):三张同等级的牌。 //rank-3,1,1 3110 30 3
7,两对(Two Pair):两对不同等级的牌。 //rank-2,2,1 2210 20 2
8,一对(One Pair):一对同等级的牌。 //rank-2,1,1,1 2111 21 2-1=1
9,高牌(High Card):如果没有以上组合,则根据最高的单张牌判断胜负。*/ //rank 1,1,1,1,1, 1111 1-1=0
答案:
int num_in_rank[13]; //读取牌面字符,CASE成数子,数组下标代表牌面,++
int num_in_suit[4]; //同上,数组下标代表数字,++,5同花,4张,3张,2张,遍历一次就行,return结束函数bool straight, flush, four, three; //唯一情况
int pairs; /* can be 0, 1, or 2 */ //两种情况 2,2,1,需要++计数全局变量,不需要传递参数
for ( ;; ) {
read_cards();
analyze_hand();
print_result();
}void read_cards(void);
//都会对前两个字符进行识别,剩余字符不是空白字符,算非法输入,然后写入信息
// 处理这一行的剩余字符
while ((c = getchar()) != '\n') {
if (c != ' ' && c != '\t')
bad_card = true;
}
void analyze_hand(void);//顺子分析:找到第一张出现的牌面,num_in_rank[i]不等于0的时候
//开始计数,到下一张不为0的牌面,int n_consective = 0;5是顺子
void print_result(void);链接IF
#include <stdio.h> #include <stdbool.h> void read_cards(void); void analyze_hand(void); void print_result(void); int num_in_rank[13]; int num_in_suit[4]; bool straight, flush, four, three; int pairs; /* can be 0, 1, or 2 */ int main(void) { for ( ;; ) { read_cards(); analyze_hand(); print_result(); } return 0; } void print_result(void) { if (straight && flush) { printf("Straight flush\n"); } else if (four) { printf("Four\n"); } else if (three && (pairs == 1)) { printf("Full hourse\n"); } else if (flush) { printf("Flush\n"); } else if (straight) { printf("Straight\n"); } else if (three && (pairs == 0)) { printf("Three\n"); } else if (pairs == 2) { printf("Two pairs\n"); } else if (pairs == 1) { printf("One pair\n"); } else { printf("High card\n"); } printf("\n"); } void analyze_hand(void) { /* 初始化 */ straight = false; flush = false; four = false; three = false; pairs = 0; /* 检查是否为同花 */ for (int i = 0; i < 4; i++) { if (num_in_suit[i] == 5) { flush = true; } } /* 检查是否为顺子 */ int idx = 0; while (num_in_rank[idx] == 0) { idx++; } // num_in_rank[idx] != 0; int n_consective = 0; while(idx < 13 && num_in_rank[idx] != 0) { n_consetive++; idx++; } if (n_consective == 5) { straight = true; return; } /* 判断四张,三张,两张 */ for (int i = 0; i < 13; i++) { if (num_in_rank[i] == 4) { four = true; } else if (num_in_rank[i] == 3) { three = true; } else if (num_in_rank[i] == 2) { pairs++; } } } void read_cards(void) { // 初始化操作 bool in_hand[4][13] = { false }; for (int i = 0; i < 13; i++) { num_in_rank[i] = 0; } for (int i = 0; i < 4; i++) { num_in_suit[i] = 0; } // 读取5张卡牌 int cards_read = 0; while (cards_read < 5) { bool bad_card = false; printf("Enter a card: "); char c = getchar(); int rank; switch (c) { case '0': exit(0); 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; } c = getchar(); int suit; switch (c) { case 'd':case 'D': suit = 0; break; case 'c':case 'C': suit = 1; break; case 'h':case 'H': suit = 2; break; case 's':case 'S': suit = 3; break; default: bad_card = true; } // 处理这一行的剩余字符 while ((c = getchar()) != '\n') { if (c != ' ' && c != '\t') bad_card = true; } if (bad_card) { printf("Bad card; ignored.\n"); } else if (in_hand[suit][rank]) { printf("Duplicate card; ignored.\n"); } else { in_hand[suit][rank] = true; cards_read++; num_in_rank[rank]++; num_in_suit[suit]++; } } }
题目三:简答题(外部变量,局部变量),FIBNACCI
(a) 什么是局部变量,什么是外部变量,它们的作用域分别是什么?
(b) 存储期限有哪些?局部变量默认的存储期限是什么?怎么改变局部变量的存储期限?
(c) 请实现 next_fib() 函数,它可以输出下一个Fibonacci数列的值
long long next_fib(void) {
}
int main(void) {
// foo(); // Fibnacii: 0, 1, 1, 2, 3, 5, 8, 13, 21, ...
printf("next_fib() = %lld\n", next_fib()); // 1
printf("next_fib() = %lld\n", next_fib()); // 1
printf("next_fib() = %lld\n", next_fib()); // 2
printf("next_fib() = %lld\n", next_fib()); // 3
printf("next_fib() = %lld\n", next_fib()); // 5
return 0;
}
解答:
(a),局部变量是声明在函数内部的变量,块作用域,全局变量是声明在函数外部的变量,拥有文件作用域
(b),静态存储期限和自动存储期限,寄存器存储期限,存储期限就是变量在程序运行过程中存在的时间长度。
局部变量的存储单元在函数调用时"自动"分配,在函数返回时自动回收,即自动存储期限
可以使用static
关键字将局部变量声明为静态变量。这样,变量的存储期限将变为整个程序的执行周期,而不是局部作用域内的执行周期
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
long long next_fib(void) {
static long long now = 0;
static long long next = 1;
long long result = now;
now = next;
next = result + now;
return result;
}
int main(void) {
// foo(); // Fibnacii: 0, 1, 1, 2, 3, 5, 8, 13, 21, ...
printf("next_fib() = %lld\n", next_fib()); // 1
printf("next_fib() = %lld\n", next_fib()); // 1
printf("next_fib() = %lld\n", next_fib()); // 2
printf("next_fib() = %lld\n", next_fib()); // 3
printf("next_fib() = %lld\n", next_fib()); // 5
printf("next_fib() = %lld\n", next_fib()); // 5
printf("next_fib() = %lld\n", next_fib()); // 5
printf("next_fib() = %lld\n", next_fib()); // 5
printf("next_fib() = %lld\n", next_fib()); // 5
printf("next_fib() = %lld\n", next_fib()); // 5
return 0;
}