顶级太阳 发表于 2022-12-25 20:57:05

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这一步了,按照程序应该开始洗牌函数了。为了查看是不是开始洗牌,我在函数的第一行进行了输出,但是运行的时候没有出现这一个输出。运行程序长时间不退出,也没有反映。请教,这是什么原因,我错在哪里?

人造人 发表于 2022-12-25 21:12:01

先把编译器的警告开到最大看看

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$

人造人 发表于 2022-12-25 21:49:55

问题有点多,先这样吧

//洗牌、发牌、显示分模块

#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;
}

zhangjinxuan 发表于 2022-12-26 08:17:55

你其实已经洗牌过了,可能是后面输出了个 \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;
}

zhangjinxuan 发表于 2022-12-26 08:44:47

现在这个程序已经可以完全正常运行了:
//洗牌、发牌、显示分模块

#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;
}

zhangjinxuan 发表于 2022-12-26 08:46:21

人造人 发表于 2022-12-25 21:49
问题有点多,先这样吧

这样实现shuffle函数的算法效率未免很低

顶级太阳 发表于 2022-12-26 15:23:45

人造人 发表于 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没有意义。

人造人 发表于 2022-12-26 16:07:18

第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:11:01

人造人 发表于 2022-12-26 16:07
第13行 j=(rand()*54)/1, 我考虑的是取0~54之间的随机数,除以1是想要取这个数的整数部分。
那也不对吧? ...

谢谢,我继续加强一下伪随机数的部分。但是rand()的结果不应该是0~1之间的么?为什么会出现1234那么大?

人造人 发表于 2022-12-26 16:21:58

顶级太阳 发表于 2022-12-26 16:11
谢谢,我继续加强一下伪随机数的部分。但是rand()的结果不应该是0~1之间的么?为什么会出现1234那么大 ...

那么就再百度 rand 函数
你看一下 rand 函数的声明

int rand(void);


还有我的代码里面

printf("%d ", rand());

看清楚,是 %d

人造人 发表于 2022-12-26 16:23:21

顶级太阳 发表于 2022-12-26 16:11
谢谢,我继续加强一下伪随机数的部分。但是rand()的结果不应该是0~1之间的么?为什么会出现1234那么大 ...

这样的话,我就能理解你的这个表达式了
j=(rand()*54)/1

顶级太阳 发表于 2022-12-26 19:24:42

人造人 发表于 2022-12-26 16:07
第13行 j=(rand()*54)/1, 我考虑的是取0~54之间的随机数,除以1是想要取这个数的整数部分。
那也不对吧? ...

百度好半天,看明白了,rand()的结果是0~32767之间的一个随机值。所以为了获得某一个数以下的随机整数,需要对获得的随机数取余。比如这个题目里54张扑克,要取随机一个0~54之间的数,就需要用rand()%54,这样获得的就是54以内的一个整数。谢谢。

顶级太阳 发表于 2022-12-26 19:28:29

zhangjinxuan 发表于 2022-12-26 08:46
这样实现shuffle函数的算法效率未免很低

我考虑的每一张扑克都重新随机抽取,然后逐个比较的shuffle算法是错误的,有可能造成运算时间特别长。你的算法确实简单,一共运行53次就可以结束。谢谢。

人造人 发表于 2022-12-26 19:38:04

顶级太阳 发表于 2022-12-26 19:24
百度好半天,看明白了,rand()的结果是0~32767之间的一个随机值。所以为了获得某一个数以下的随机整数 ...

比如这个题目里54张扑克,要取随机一个0~54之间的数,就需要用rand()%54
要得到 0~54 之间的数,应该 rand() % 55

比如这个题目里54张扑克,要取随机一个0~   53    之间的数,就需要用rand()%54

你的问题就是对边界值上马马虎虎的,然后就数组越界访问了

zhangjinxuan 发表于 2022-12-26 20:09:12

顶级太阳 发表于 2022-12-26 19:28
我考虑的每一张扑克都重新随机抽取,然后逐个比较的shuffle算法是错误的,有可能造成运算时间特别长。 ...

^_^
页: [1]
查看完整版本: s1e31我写的子函数为什么不进入执行呢?