s1e31我写的子函数为什么不进入执行呢?
本帖最后由 顶级太阳 于 2022-12-25 20:59 编辑s1e31动动手题目:
实现一个洗牌程序。所谓洗牌程序,就是将所有的扑克牌放入一个数组中,要求把数组内的扑克牌顺序随机打乱,然后输出。
要求实现的输出内容如下:
我写的代码如下:
//洗牌、发牌、显示分模块
#include<stdio.h>
#include<stdlib.h>
//洗牌:在54个元素的全为0数组里填入1-54的数字
void shuffle(int poker[])
{
int i,j,m;
printf("洗牌进行中。。。");//测试程度进度用,临时测试用,现有程序没有运行到这一行。why?
for(i=0;i<54;i++)
{
pos_1: j=(rand()*54)/1;
for(m=0;m<i;m++)
{
if(j=poker)goto pos_1; //与已有值遍历进行比较,如果已经有填入,重新抽取随机数
}
poker=j;
printf("%d",i+1);//显示进行到第几张扑克 ,临时测试用
}
}
//发牌deal:轮流将poket交给不同player的分发
void deal(int poket[],int player1[],int player2[],int player3[])
{
int i,j;
for(i=0;i<52;i++)
{
j=0;
switch(i%3)
{
case 0: player1=poket;break;
case 1: player2=poket;break;
case 2: player3=poket;j++; break;
}
}
}
//显示show:显示每个人手里的扑克内容
void show(char name,int player[])
{
char poket={"方1","方2","方3","方4","方5","方6","方7","方8","方9","方10","方J","方Q","方K","梅1","梅2","梅3","梅4","梅5","梅6","梅7","梅8","梅9","梅10","梅J","梅Q","梅K","红1","红2","红3","红4","红5","红6","红7","红8","红9","红10","红J","红","红K","黑1","黑2","黑3","黑4","黑5","黑6","黑7","黑8","黑9","黑10","黑J","黑Q","黑K","小王","大王"};
printf("%s手上的牌是:",&name);
for(int i=0;i<14;i++)
{
printf("%s",poket]);
}
printf("\n");
}
int main()
{
int player1,player2,player3;
char name1,name2,name3,yorn;
int poker={0};
printf("请输入1号玩家的名字:");
scanf("%s",&name1);
printf("请输入2号玩家的名字:");
scanf("%s",&name2);
printf("请输入3号玩家的名字:");
scanf("%s",&name3);
step: printf("方=方角,梅=梅花,红=红桃,黑=黑桃\n"); //现在程序运行到了这,往下的洗牌函数不运行了,为什么?
shuffle(poker);//洗牌
deal(poker,player1,player2,player3);//发牌
show(name1,player1);//亮牌
show(name2,player2);//亮牌
show(name3,player3);//亮牌
printf("重新洗牌(Y/N)?");
if(getchar()=='Y') goto step;
return 0;
}
通过改错,已经编译成功,不报错了。然后尝试运行,现在屏幕显示运行到了主程序step这一步了,按照程序应该开始洗牌函数了。为了查看是不是开始洗牌,我在函数的第一行进行了输出,但是运行的时候没有出现这一个输出。运行程序长时间不退出,也没有反映。请教,这是什么原因,我错在哪里? 先把编译器的警告开到最大看看
sh-5.1$ gcc -g -Wall -o main main.c
main.c: In function ‘shuffle’:
main.c:15:28: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
15 | if(j=poker)goto pos_1; //与已有值遍历进行比较,如果已经有填入,重新抽取随机数
| ^
main.c: In function ‘main’:
main.c:72:28: error: expected ‘;’ before ‘;’
72 | show(name1,player1);//亮牌
| ^~
| ;
main.c:57:32: warning: unused variable ‘yorn’ [-Wunused-variable]
57 | char name1,name2,name3,yorn;
| ^~~~
sh-5.1$
问题有点多,先这样吧
//洗牌、发牌、显示分模块
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//洗牌:在54个元素的全为0数组里填入1-54的数字
void shuffle(int poker[]) {
int i, j, m;
printf("洗牌进行中。。。"); //测试程度进度用,临时测试用,现有程序没有运行到这一行。why?
for(i = 0; i < 54; i++) {
pos_1:
//j = (rand() * 54) / 1; // 除以 1?
// 什么意思?
j = (rand() % 54) + 1;
for(m = 0; m < i; m++) {
// if(j=poker)goto pos_1;
// //与已有值遍历进行比较,如果已经有填入,重新抽取随机数
if(j == poker)
goto pos_1; //与已有值遍历进行比较,如果已经有填入,重新抽取随机数
}
poker = j;
printf("%d", i + 1); //显示进行到第几张扑克 ,临时测试用
}
}
#if 0
//发牌deal:轮流将poket交给不同player的分发
void deal(int poket[], int player1[], int player2[], int player3[]) {
int i, j;
for(i = 0; i < 52; i++) {
j = 0;
// 错
/*
switch(i % 3) {
case 0:
player1 = poket;
break;
case 1:
player2 = poket;
break;
case 2:
player3 = poket;
j++;
break;
}
*/
}
}
#else
void deal(int poket[], int player1[], int player2[], int player3[]) {
int *player = {player1, player2, player3};
//for(size_t i = 0; i < 52; ++i)*player++ = poket;
for(size_t i = 0; i < 42; ++i)*player++ = poket; // 最简单的改法了
// 不然了
// 54 无法平分3份
}
#endif
//显示show:显示每个人手里的扑克内容
//void show(char name, int player[]) {
void show(const char *name, int player[]) {
char poket = {
"方1","方2", "方3", "方4","方5","方6", "方7", "方8","方9",
"方10", "方J", "方Q", "方K","梅1","梅2", "梅3", "梅4","梅5",
"梅6","梅7", "梅8", "梅9","梅10", "梅J", "梅Q", "梅K","红1",
"红2","红3", "红4", "红5","红6","红7", "红8", "红9","红10",
"红J","红","红K", "黑1","黑2","黑3", "黑4", "黑5","黑6",
"黑7","黑8", "黑9", "黑10", "黑J","黑Q", "黑K", "小王", "大王"};
//printf("%s手上的牌是:", &name);
printf("%s手上的牌是:", name);
for(int i = 0; i < 14; i++) {
// printf("%s", poket]); // 你上面弄到的player取值范围是什么?
// 1 到 54 吧?
// 用 54 直接索引这个数组?
printf("%s", poket - 1]);
}
printf("\n");
}
// 错的离谱
/*
int main() {
int player1, player2, player3;
// char name1,name2,name3,yorn;
char name1, name2, name3;
int poker = {0};
printf("请输入1号玩家的名字:");
scanf("%s", &name1); // ???
printf("请输入2号玩家的名字:");
scanf("%s", &name2); // 这什么操作?
printf("请输入3号玩家的名字:");
scanf("%s", &name3); // 这?
step:
printf(
"方=方角,梅=梅花,红=红桃,黑=黑桃\n"); //现在程序运行到了这,往下的洗牌函数不运行了,为什么?
shuffle(poker); //洗牌
deal(poker, player1, player2, player3); //发牌
// show(name1,player1);//亮牌
show(name1, player1); //亮牌
show(name2, player2); //亮牌
show(name3, player3); //亮牌
printf("重新洗牌(Y/N)?");
if(getchar() == 'Y')
goto step;
return 0;
}
*/
int main(void) {
srand(time(NULL)); // 连srand也没有,你这随机数"随机"吗?
int player1, player2, player3; // 14 + 14 + 14 等于几?
// 42 对吧?
// 54 张牌,42 个位置,有什么问题?
// char name1,name2,name3,yorn;
char name1, name2, name3;
//int poker = {0};
printf("请输入1号玩家的名字:");
scanf("%s", name1);
printf("请输入2号玩家的名字:");
scanf("%s", name2);
printf("请输入3号玩家的名字:");
scanf("%s", name3);
step:
printf("方=方角,梅=梅花,红=红桃,黑=黑桃\n"); //现在程序运行到了这,往下的洗牌函数不运行了,为什么?
int poker = {0}; // 放到这里就全0了
// 这个函数要执行的条件是什么?
// poker全0对不对?
shuffle(poker); //洗牌
deal(poker, player1, player2, player3); //发牌
// 行也不换?
printf("\n");
// show(name1,player1);//亮牌
show(name1, player1); //亮牌
show(name2, player2); //亮牌
show(name3, player3); //亮牌
// 这
getchar(); // '\n'
printf("重新洗牌(Y/N)?");
if(getchar() == 'Y')
goto step; // 从这里转上去之后,poker还是全0吗?
return 0;
}
你其实已经洗牌过了,可能是后面输出了个 \r 之类的
//洗牌、发牌、显示分模块
#include<stdio.h>
#include<stdlib.h>
//洗牌:在54个元素的全为0数组里填入1-54的数字
void shuffle(int poker[])
{
int i,j,m;
printf("洗牌进行中。。。\n");//测试程度进度用,临时测试用,现有程序没有运行到这一行。why?
for(i=0;i<54;i++)
{
pos_1: j=(rand()*54)/1;
for(m=0;m<i;m++)
{
if(j=poker)goto pos_1; //与已有值遍历进行比较,如果已经有填入,重新抽取随机数
}
poker=j;
printf("%d",i+1);//显示进行到第几张扑克 ,临时测试用
}
}
//发牌deal:轮流将poket交给不同player的分发
void deal(int poket[],int player1[],int player2[],int player3[])
{
int i,j;
for(i=0;i<52;i++)
{
j=0;
switch(i%3)
{
case 0: player1=poket;break;
case 1: player2=poket;break;
case 2: player3=poket;j++; break;
}
}
}
//显示show:显示每个人手里的扑克内容
void show(char name,int player[])
{
char poket={"方1","方2","方3","方4","方5","方6","方7","方8","方9","方10","方J","方Q","方K","梅1","梅2","梅3","梅4","梅5","梅6","梅7","梅8","梅9","梅10","梅J","梅Q","梅K","红1","红2","红3","红4","红5","红6","红7","红8","红9","红10","红J","红","红K","黑1","黑2","黑3","黑4","黑5","黑6","黑7","黑8","黑9","黑10","黑J","黑Q","黑K","小王","大王"};
printf("%s手上的牌是:",&name);
for(int i=0;i<14;i++)
{
printf("%s",poket]);
}
printf("\n");
}
int main()
{
int player1,player2,player3;
char name1,name2,name3,yorn;
int poker={0};
printf("请输入1号玩家的名字:");
scanf("%s",&name1);
printf("请输入2号玩家的名字:");
scanf("%s",&name2);
printf("请输入3号玩家的名字:");
scanf("%s",&name3);
step: printf("方=方角,梅=梅花,红=红桃,黑=黑桃\n"); //现在程序运行到了这,往下的洗牌函数不运行了,为什么?
shuffle(poker);//洗牌
deal(poker,player1,player2,player3);//发牌
show(name1,player1); //亮牌
show(name2,player2);//亮牌
show(name3,player3);//亮牌
printf("重新洗牌(Y/N)?");
if(getchar()=='Y') goto step;
return 0;
}
现在这个程序已经可以完全正常运行了:
//洗牌、发牌、显示分模块
#include<stdio.h>
#include<stdlib.h>
//洗牌:在54个元素的全为0数组里填入1-54的数字
void shuffle(int poker[])
{
int i,j,m;
for (i=0;i<54;++i) //改了算法,我们应该要有初始的数组
poker=i;
printf("洗牌进行中。。。\n");//测试程度进度用,临时测试用,现有程序没有运行到这一行。why?
for(i=1;i<54;i++) //这种洗牌算法真的很简单,从前往后,随机选数,当前位置和随机选到的位置互换就好
{
j=rand()%i;
m=poker;
poker=poker;
poker=m;
}
}
//发牌deal:轮流将poket交给不同player的分发
void deal(int poket[],int player1[],int player2[],int player3[])
{
int i,j,p1=0,p2=0,p3=0; //p1p2p3分别发了多少牌,你这样做有问题
for(i=0;i<42;i++) //每人到底几张?
{
j=0;
switch(i%3)
{
case 0: player1=poket;break;
case 1: player2=poket;break;
case 2: player3=poket;j++; break;
}
}
}
//显示show:显示每个人手里的扑克内容
void show(char name[],int player[]) //name应为数组
{
const char *poket={"方1","方2","方3","方4","方5","方6","方7","方8","方9","方10","方J","方Q","方K","梅1","梅2","梅3","梅4","梅5","梅6","梅7","梅8","梅9","梅10","梅J","梅Q","梅K","红1","红2","红3","红4","红5","红6","红7","红8","红9","红10","红J","红","红K","黑1","黑2","黑3","黑4","黑5","黑6","黑7","黑8","黑9","黑10","黑J","黑Q","黑K","小王","大王"};
printf("%s手上的牌是:",name); //不需要 &
for(int i=0;i<14;i++)
{
printf("%s ",poket]);
}
printf("\n");
}
int main()
{
int player1,player2,player3;
char name1={},name2={},name3={},yorn; //这里
int poker={0};
printf("请输入1号玩家的名字:");
scanf("%s",&name1);
printf("请输入2号玩家的名字:");
scanf("%s",&name2);
printf("请输入3号玩家的名字:");
scanf("%s",&name3);
step: printf("方=方角,梅=梅花,红=红桃,黑=黑桃\n"); //现在程序运行到了这,往下的洗牌函数不运行了,为什么?
shuffle(poker);//洗牌
deal(poker,player1,player2,player3);//发牌
show(name1,player1); //亮牌
show(name2,player2);//亮牌
show(name3,player3);//亮牌
printf("重新洗牌(Y/N)?");
getchar(); //过滤 \n
if(getchar()=='Y') goto step;
return 0;
}
人造人 发表于 2022-12-25 21:49
问题有点多,先这样吧
这样实现shuffle函数的算法效率未免很低 人造人 发表于 2022-12-25 21:49
问题有点多,先这样吧
第13行 j=(rand()*54)/1, 我考虑的是取0~54之间的随机数,除以1是想要取这个数的整数部分。
第19行,确实是个人习惯,一直不习惯=与==的区别,比较和定义之间不同。
第33行,发牌阶段确实我写错了。我的想法是,用牌的数量除以3,这样每一次会指向不同的case,达到轮流交给不同人的目的,player应该用【j】,而不是【i】。
第73行,我考虑的是用player里面存的整数来取poket这个数组内相应的数值。
多说一句,这一程序我是这样考虑的,在洗牌阶段,通过随机数将54个数值存入poker数组,形成一个杂乱的整数数组。在发牌阶段,将这个数组里的数值分给3个对应不同人的整数数组。在显示阶段,将数组里的整数对应到基本字符数组poket数组上。这样做的目的是减少内存占用。过程中一直用整数数组,只是最后用一下字符型数组。
第114行,主程序我没考虑随机数的问题,在这里加入一个srand什么意思呢?我考虑的取随机数只是在洗牌shuffle的子函数里。跟这个主函数没有关系的。
第115行,是我算错了。从小不玩扑克,真的不知道54张牌,3个人玩,一人几张。当时现算的,脑子一抽算错了。一人应该18张,不知道当时怎么算的了,算的结果好像还剩了2张。哈哈哈哈,抱歉。
第131行,我翻回去看了,我是在设置这个数组的时候置0的,在我程序第58行。在你给的这个位置我没有置0呀。
第152行,我在洗牌程序里做随机数,没有必要在主程序里一定是0,在主程序里完全置0没有意义。 第13行 j=(rand()*54)/1, 我考虑的是取0~54之间的随机数,除以1是想要取这个数的整数部分。
那也不对吧?
假设这个rand()返回的是 1234
1234 * 54 = 66636
除以 1 就不能理解了,一个整数乘以一个整数会出现小数部分吗?
再说了,除以1怎么就取整数部分了?
sh-5.1$ cat main.c
#include <stdio.h>
#include <stdlib.h>
void print(void) {
for(size_t i = 0; i < 10; ++i) {
printf("%d ", rand());
}
printf("\n");
}
int main(void) {
print();
return 0;
}
sh-5.1$ gcc -g -Wall -o main main.c
sh-5.1$ ./main
1804289383 846930886 1681692777 1714636915 1957747793 424238335 719885386 1649760492 596516649 1189641421
sh-5.1$ ./main
1804289383 846930886 1681692777 1714636915 1957747793 424238335 719885386 1649760492 596516649 1189641421
sh-5.1$ ./main
1804289383 846930886 1681692777 1714636915 1957747793 424238335 719885386 1649760492 596516649 1189641421
sh-5.1$ ./main
1804289383 846930886 1681692777 1714636915 1957747793 424238335 719885386 1649760492 596516649 1189641421
sh-5.1$ ./main
1804289383 846930886 1681692777 1714636915 1957747793 424238335 719885386 1649760492 596516649 1189641421
sh-5.1$
随机不?
rand 叫伪随机
所以,百度 srand 函数
sh-5.1$ cat main.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void print(void) {
for(size_t i = 0; i < 10; ++i) {
srand(time(NULL));
printf("%d ", rand());
}
printf("\n");
}
int main(void) {
print();
return 0;
}
sh-5.1$ gcc -g -Wall -o main main.c
sh-5.1$ ./main
496724219 496724219 496724219 496724219 496724219 496724219 496724219 496724219 496724219 496724219
sh-5.1$ ./main
1265208624 1265208624 1265208624 1265208624 1265208624 1265208624 1265208624 1265208624 1265208624 1265208624
sh-5.1$ ./main
2035418005 2035418005 2035418005 2035418005 2035418005 2035418005 2035418005 2035418005 2035418005 2035418005
sh-5.1$ ./main
671787692 671787692 671787692 671787692 671787692 671787692 671787692 671787692 671787692 671787692
sh-5.1$ ./main
1436671818 1436671818 1436671818 1436671818 1436671818 1436671818 1436671818 1436671818 1436671818 1436671818
sh-5.1$
那么,srand 函数应该放在哪里呢?
放在这里对吧?
我可见过这样做的同学,而且还不少了
人造人 发表于 2022-12-26 16:07
第13行 j=(rand()*54)/1, 我考虑的是取0~54之间的随机数,除以1是想要取这个数的整数部分。
那也不对吧? ...
谢谢,我继续加强一下伪随机数的部分。但是rand()的结果不应该是0~1之间的么?为什么会出现1234那么大? 顶级太阳 发表于 2022-12-26 16:11
谢谢,我继续加强一下伪随机数的部分。但是rand()的结果不应该是0~1之间的么?为什么会出现1234那么大 ...
那么就再百度 rand 函数
你看一下 rand 函数的声明
int rand(void);
还有我的代码里面
printf("%d ", rand());
看清楚,是 %d
顶级太阳 发表于 2022-12-26 16:11
谢谢,我继续加强一下伪随机数的部分。但是rand()的结果不应该是0~1之间的么?为什么会出现1234那么大 ...
这样的话,我就能理解你的这个表达式了
j=(rand()*54)/1
人造人 发表于 2022-12-26 16:07
第13行 j=(rand()*54)/1, 我考虑的是取0~54之间的随机数,除以1是想要取这个数的整数部分。
那也不对吧? ...
百度好半天,看明白了,rand()的结果是0~32767之间的一个随机值。所以为了获得某一个数以下的随机整数,需要对获得的随机数取余。比如这个题目里54张扑克,要取随机一个0~54之间的数,就需要用rand()%54,这样获得的就是54以内的一个整数。谢谢。 zhangjinxuan 发表于 2022-12-26 08:46
这样实现shuffle函数的算法效率未免很低
我考虑的每一张扑克都重新随机抽取,然后逐个比较的shuffle算法是错误的,有可能造成运算时间特别长。你的算法确实简单,一共运行53次就可以结束。谢谢。 顶级太阳 发表于 2022-12-26 19:24
百度好半天,看明白了,rand()的结果是0~32767之间的一个随机值。所以为了获得某一个数以下的随机整数 ...
比如这个题目里54张扑克,要取随机一个0~54之间的数,就需要用rand()%54
要得到 0~54 之间的数,应该 rand() % 55
比如这个题目里54张扑克,要取随机一个0~ 53 之间的数,就需要用rand()%54
你的问题就是对边界值上马马虎虎的,然后就数组越界访问了
顶级太阳 发表于 2022-12-26 19:28
我考虑的每一张扑克都重新随机抽取,然后逐个比较的shuffle算法是错误的,有可能造成运算时间特别长。 ...
^_^
页:
[1]