C语言基础04——数组 。冒泡排序、三子棋、扫雷、向有序序列中插入数据、逆序数组元素

目录

一维数组

二维数组

数组越界

数组作为函数参数

数组的应用实例1:三子棋

数组的应用实例2:扫雷游戏

数组练习


- 数组如果初始化,可以不指定数组大小。并且数组大小不能传入一个变量。

- 数组是一组相同类型元素的组合:int类型数组只能存储int类型、char类型数组只能存储char类型

- 数组在内存方面存储的时候,数组中元素的内存地址是连续的。

- 所有的数组都是拿“首元素的内存地址”作为整个数组对象的内存地址。
  数组中首元素的内存地址作为整个数组对象的内存地址。

- 数组中每一个元素都是有下标的,下标从零开始,以1递增。最后一个元素的下标:数组长度-1
  下标非常重要,我们对数组中元素进行“存取”的时候,都要通过下标来进行

一维数组

  • 一维数组的创建和初始化

    #include 
    #include 
    
    int main()
    {
        //一维数组的定义及初始化
        //数据元素类型 数组名[常量/常量表达式]={};  //C99之前,[]中必须是一个常量,不能使用变量。
    
        //C99语法:变长数组:数组的大小可以是变量。不建议这样使用
        //int n = 3;
        //int arr[n];
    
        //完全初始化
        //int arr[10] = {1,2,3,4,5,6,7,8,9,};
    
        //不完全初始化,其余值为0。
        //int arr[10] = {1,2,3,4,5};
        //这也是不完全初始化,我们只是为下标为1的元素初始化值为10,其他默认初始化值为0。
        //int arr[10] = {10};
    
        //数组创建时,可以不指定数组大小,但是需要初始化。此时,数组根据其初始化元素个数来确定其大小。
        //int arr[] ={1,2,3,4,5};  //等同于int arr[5] ={1,2,3,4,5};
    
        //字符数组的初始化
        //char ch1[5] ={'d','o','g'};     //其中存储的是'd','o','g','\0','\0'
        //char ch2[] ={'d','o','g'};      //其中存储的是'd','o','g'
    
        //因为字符串是以\0结尾的,所以如果是以字符串为值初始化,则这个\0也会存储到字符数组中
        //char ch3[5] = "cat";    //其中存储的是'c','a','t','\0','\0'  最后面这个0是默认补充的
        //char ch4[] = "cat";     //其中存储的是'c','a','t','\0'  ,数组大小为4
    
        //以下两种数组初始化的区别
        char ch5[] ="dog";
        char ch6[] ={'d','o','g'};
        //以%s形式打印,遇到\0才会停止打印
        printf("%s\n",ch5);//dog   //ch5数组中存储了dog'\0',当打印时碰到\0,就会停止
        printf("%s\n",ch6);//dogdog //ch6数组中只存储了dog,打印完dog不会停止,直到碰见\0才会停止打印
        //求字符串长度也是,碰到\0才停止。
        printf("%d\n",strlen(ch5)); //3
        printf("%d\n",strlen(ch6)); //6,这里的6是个随机值。什么时候碰到\0,什么时候停止计算长度。
        
        return 0;
    
    
  • 一维数组的使用

    //数组的大小需要通过计算:数组总大小/一个数组元素大小 = 数组大小。
    //数组中元素下标从0开始,到(数组大小-1)结束。使用下标引用,也就是[]访问数组元素。
    #include 
    
    int main()
    {
        //数组的不完全初始化
        int arr[10] = {0};
    
        //计算数组的元素个数
        int sz = sizeof (arr)/sizeof (arr[0]);
        //对数组中某个元素赋值,需要通过数组下标访问。
        int i;
        for( i=0 ; i<10 ; i++)
        {
            arr[i] = i;
            printf("%d ",arr[i]);   //0 1 2 3 4 5 6 7 8 9
        }
        return 0;
    }
    
  • 一维数组在内存中的存储

    • 一维数组在内存中是连续存放的。并且随着数组下标的增长,地址是由低到高变化的。·

      //%p —— 按地址的格式打印,内存地址以十六进制存储的。
      //%x —— 打印十六进制。
      //%p与%x的区别:%x会省略掉前面的0,%p不会省略。
      int main()
      {
      
          //一维数组在内存中是连续存放的。并且随着数组下标的增长,地址是由低到高变化的。
          int arr[10] = {0};
          int i;
          for(i=0 ; i<10 ; i++)
          {
              printf("&arr[%d] = %p\n",i,&arr[i]);
          }
          //这里每个数组元素的内存地址差4,是因为int类型占4个字节。
          //&arr[0] = 000000d0819ff800
          //&arr[1] = 000000d0819ff804
          //&arr[2] = 000000d0819ff808
          //&arr[3] = 000000d0819ff80c
          //&arr[4] = 000000d0819ff810
          //&arr[5] = 000000d0819ff814
          //&arr[6] = 000000d0819ff818
          //&arr[7] = 000000d0819ff81c
          //&arr[8] = 000000d0819ff820
          //&arr[9] = 000000d0819ff824
          return 0;
      }
      
    • 使用指针变量

      #include 
      
      int main()
      {
          int arr[10] = {1,3,5,7,9,11,13,15,17,19};
          int* p = arr;  //数组名是数组首元素的地址
          int i;
          for(i=0 ; i<10 ; i++)
          {
              //*p 解引用
              printf("%d ",*p); //1 2 3 4 5 6 7 8 9 10
              //因为p是指针变量,又是int类型,所以一次跳4个。如果是char类型指针,则+1指每次跳一个。
              p ++;
          }
          return 0;
      

二维数组

  • 二维数组的创建和初始化

    //二维数组是一个特殊的一维数组,特殊在这个一维数组中的每一个元素都是一个数组。
    
    #include 
    
    int main()
    {
        //二维数组的完全初始化。[0][0-3]:1、2、3、4 , [1][0-3]:5、6、7、8   [2][0-3]:9、10、11、12
        //int arr[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
    
        //不完全初始化。没有初始化的赋值0。如果是字符数组,则赋值'\0'。
        //[0][0-3]:1、2、3、4 , [1][0-3]:5、6、7、0   [2][0-3]:0、0、0、0
        //int arr[3][4] ={1,2,3,4,5,6,7};
    
        //二维数组如果在定义的同时初始化,是可以省略行的,也就是第一个[]里的值。它可以根据初始化的内容,来补全[]。
        // 这里就是arr[2][4] ,因为是有六个元素,[2]够用,所以是[2][4]。如果里面有9个元素,则补全为[3][4]
        //[0][0-3]:1、2、3、4 , [1][0-3]:5、6、0、0
        //int arr[][4] = {1,2,3,4,5,6};
    
        //这样初始化,其元素值:
        //[0][0-3]:1、2、0、0 , [1][0-3]:3、4、0、0   [2][0-3]:5、6、0、0
        //int arr[3][4] = {{1,2},{3,4},{5,6}};
        
        return 0;
    }
    
  • 二维数组的使用

    /*
        关于二维数组中元素的:读和改
            a[二维数组中一维数组的下标][二维数组中的一维数组中的元素下标]
            a[0][0]:表示第一个一维数组中的第一个元素。
            a[3][100]:表示第四个一维数组中的第101个元素。
            对于a[3][100]来说,其中a[3]是一个整体,[100]是前面a[3]直接结束的结果然后再下标100,
     */
    #include 
    
    int main()
    {
        int arr[3][4] ={0};
        int i,j;
        for(i=0 ; i < 3 ; i++)
        {
            for(j=0 ; j<4 ; j++)
            {
                arr[i][j] = i*4 + j +1;
                printf("%d ",arr[i][j]);
                //1 2 3 4
                //5 6 7 8
                //9 10 11 12
            }
            printf("\n");
        }
        return 0;
    }
    
  • 二维数组在内存中的存储

    #include 
    
    int main()
    {
        int arr[3][4] ={0};
        int i,j;
        for(i=0 ; i < 3 ; i++)
        {
            for(j=0 ; j<4 ; j++)
            {
                printf("arr[%d][%d] = %p\n",i,j,&arr[i][j]);
            }
            printf("\n");
        }
        //arr[0][0] = 000000fb643ffc00
        //arr[0][1] = 000000fb643ffc04
        //arr[0][2] = 000000fb643ffc08
        //arr[0][3] = 000000fb643ffc0c
        //
        //arr[1][0] = 000000fb643ffc10
        //arr[1][1] = 000000fb643ffc14
        //arr[1][2] = 000000fb643ffc18
        //arr[1][3] = 000000fb643ffc1c
        //
        //arr[2][0] = 000000fb643ffc20
        //arr[2][1] = 000000fb643ffc24
        //arr[2][2] = 000000fb643ffc28
        //arr[2][3] = 000000fb643ffc2c
        return 0;
    }
    

    解引用

    #include 
    
    int main()
    {
        int arr[3][4] = {{1,2},{3,4},{5,6}};
        int i,j;
        int* p = &arr[0][0]; //这里的&arr[0][0]等同于arr,因为数组存储的是首元素的地址
        for(i=0 ; i < 12 ; i++)
        {
            printf("%d ",*p); //1 2 0 0 3 4 0 0 5 6 0 0
            p++;
        }
    
        return 0;
    }
    

数组越界

#include 

/*
 * 数组的下标是有范围限制的。数组下标从0开始,如果有n个元素,最后一个元素的下标就是n-1
 * 如果是使用[]方法数组下标时,小于0或>n-1了,就发生数组越界。
 * C语言本身没有做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,也不意味着程序就是正确的。
 * 所以我们在写程序时,最好自己检查一下引用是否越界。
 */

int main()
{
    int arr[] = {1,2,3,4,5};
    int i;
    for(i=0 ; i<=10 ; i++)
    {
        //从5之后的数字都不是我们定义的数组中的数据,数组越界之后会取出的值不可预料。所以要做好检查。
        printf("%d ",arr[i]);  //1 2 3 4 5 32759 0 7 -641728848 78 990385215
    }
    return 0;
}

数组作为函数参数

函数的形参定义成数组也可以、定义成指针变量也可以。
- 数组作为函数参数传参时,实际传入的是数组名,而数组名是数组中首个元素的地址。所以说实际上传进去的是个指针
  • 数组名

    /*
     * 数组名是首元素的地址
     *
     * 例外:
     * 1. sizeof(数组名) 在这个方法中,我们传入的数组名,代表整个数组。所以这个方法计算的是整个数组的大小,单位:字节。
     * 2. &数组名 加了&的数组名表示整个数组,取出的是整个数组的地址。
     */
    #include 
    
    int main()
    {
        int arr[10] = {0};
    
        //1. 在sizeof方法中,数组名代表整个数组
        int sz = sizeof (arr);
        printf("%d\n",sz);  //40
    
        //这三个都是00000022165ffc30。 arr与&arr[0]都代表数组首元素。&arr代表整个数组
        //printf("%p\n",&arr[0]);
        //printf("%p\n",arr);
        //printf("%p\n",&arr);
    
        //让他们加1,看区别
        printf("%p\n",arr);     //000000b6953ffcf0
        printf("%p\n",arr+1);   //000000b6953ffcf4
    
        printf("%p\n",&arr);    //000000b6953ffcf0  十进制是:784,188,046,576
        printf("%p\n",&arr+1);  //000000b6953ffd18  十进制是:784,188,046,616
    
        //可以看出 arr+1,只加了4个字节;而&arr+1,加了40个字节。
        return 0;
    }
    
  • 冒泡排序

    /*
        冒泡排序算法
        1、每一次循环结束之后,都要找出最大的数据,放到参与比较的这堆数据的最右边。(冒出最大的那个气泡)
        2、核心:
            拿着左边的数字和右边的数字比对,当 左边 > 右边 的时候,交换位置。
    
        原始数据:
        3,2,7,6,8
        第一次循环:(最大的跑到最右边)
        2,3,7,6,8       3和2比较,2<3,所以2和3交换位置
        2,3,7,6,8       虽然不需要交换位置:但是3和7还是需要比较一次
        2,3,6,7,8       6<7 6和7交换位置
        2,3,6,7,8       虽然不需要交换位置:但是7和8还是需要比较一次
    
        经过第一次循环,此时剩下参与比较的数据:2,3,6,7
        第二次循环
        2,3,6,7         2和3比较,不需要交换位置
        2,3,6,7         3和6比较,不需要交换位置
        2,3,6,7         6和7比较,不需要交换位置
    
        经过第二次循环,此时剩下参与比较的数据:2,3,6
        第三次循环
        2,3,6       2和3比较,不需要交换位置
        2,3,6       3和6比较,不需要交换位置
    
        经过第三次循环,此时剩下参与比较的数据:2,3
        第四次循环
        2,3         2和3比较,不需要交换位置
    
    
        原始数据:9 8 10 7 6 0 11
        第一次循环:
        8 9 10 7 6 0 11     第1次比较后:交换
        8 9 10 7 6 0 11     第2次比较后:不交换
        8 9 7 10 6 0 11     第3次比较后:交换
        8 9 7 6 10 0 11     第4次比较后:交换
        8 9 7 6 0 10 11     第5次比较后:交换
        8 9 7 6 0 10 11     第6次比较后:不交换
        最终冒出的最大数据在右边:11
    
        经过第一次循环,此时剩下参与比较的数据:  8 9 7 6 0 10
        第二次循环
        8 9 7 6 0 10        第1次比较后:不交换
        8 7 9 6 0 10        第2次比较后:交换
        8 7 6 9 0 10        第3次比较后:交换
        8 7 6 0 9 10        第4次比较后:交换
        8 7 6 0 9 10        第5次比较后:不交换
        最终冒出的最大数据在右边:10
    
        经过第二次循环,此时剩下参与比较的数据:  8 7 6 0 9
        第三次循环
        7 8 6 0 9       第1次比较后:交换
        7 6 8 0 9       第2次比较后:交换
        7 6 0 8 9       第3次比较后:交换
        7 6 0 8 9       第4次比较后:不交换
        最后冒出的最大数据在右边:9
    
        经过第三次循环,此时剩下参与比较的数据:7 6 0 8
        第四次循环
        6 7 0 8     第1次比较后:交换
        6 0 7 8     第2次比较后:交换
        6 0 7 8     第3次比较后:不交换
        最后冒出的最大数据在右边:8
    
        经过第四次循环,此时剩下参与比较的数据:6 0 7
        第五次循环
        0 6 7   第1次比较后:交换
        0 6 7   第2次比较后:不交换
        最后冒出的最大数据在右边:7
    
        经过第五次循环,此时剩下参与比较的数据:0 6
        第六次循环
        0 6     第1次比较后:不交换
    
            //7条数据比6次
            //6条数据比5次
            //5条数据比4次
            //4条数据比3次
            //3条数据比2次
            //2条数据比1次
    
     */
    
    #include 
    
    void bubble_sort(int arr[],int length)
    {
    
        int i = 0;
        int j = 0;
        //10条数据要循环9次,每次经过9次判断。 n条数据,循环n-1次,判断n-1次
        //数组长度是:length。要循环n-1次,所以这里是length-1
        for(i=length-1 ; i > 0 ; i--)
        {
            for(j=0 ; jarr[j+1])
                {
                    int temp;
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }
    
    int main()
    {
        int arr[] = {9,8,10,6,2,11,23,18,42,16};
    
        int sz = sizeof(arr)/sizeof(arr[0]);
    
        //冒泡排序——将较大的数字放到右边
        bubble_sort(arr,sz); //数组传参的时候,传递的是首元素的地址。
        int i;
        for (i = 0; i 

数组的应用实例1:三子棋

在此项目的实现中,遗留问题:
- 电脑下棋太随机,有点笨,需要更改其电脑下棋实现来使他聪明一点
- 此项目中对三子棋的判断条件解了耦合,也就是说,如果是5行5列,或其他行其他列。我们的判断条件也不会有问题。(仅是行数和列数相同的时候,不相同的时候判断条件还比较多,可以自行修改实现)
  • game.h 游戏的函数声明

    //关于游戏相关的函数声明,符号声明,头文件的包含。
    #ifndef FIRST_GAME_H
    #define FIRST_GAME_H
    
    //头文件的包含
    #include 
    #include 
    #include 
    
    #define ROW 3
    #define COL 3
    
    //声明InitBoard()初始化函数
    void InitBoard(char board[ROW][COL],int row,int col);
    
    //声明DisplayBoard()函数
    void DisplayBoard(char board[ROW][COL],int row,int col);
    
    //声明playerMove()函数 ,第一个[]中的内容可以省略
    void playerMove(char board[][COL],int row,int col);
    
    //声明computerMove()
    void computerMove(char board[ROW][COL],int row,int col);
    
    //声明isWin()
    char isWin(char board[][COL],int row,int col);
    
    #endif //FIRST_GAME_H
    
  • game.c 游戏函数实现

    //游戏相关的函数实现
    
    //包含头文件
    #include "game.h"
    
    //InitBoard()函数的实现
    void InitBoard(char board[ROW][COL],int row,int col)
    {
        int i,j;
        for ( i=0 ; i =1 && x<=row && y>=1 && y<=col)
            {
                //玩家通过坐标进行下棋,如1 1就对应数组里的0 0 。如果为' '空,则说明没有被占用
                if(board[x-1][y-1] ==' ')
                {
                    board[x-1][y-1] = '*';
                    //每人只能下一次棋,所以下棋后退出循环
                    break;
                }
                else
                {
                    printf("该位置已有棋子,请重下棋子。\n");
    
                }
            }
            else
            {
                printf("输入的坐标不合法,请重新输入。\n");
            }
        }
    }
    
    
    //电脑下棋
    void computerMove(char board[ROW][COL],int row,int col)
    {
        printf("电脑(#)下棋:\n");
        //可能取的这个随机坐标,已经有值了,所以我们把它放入循环
        while(1)
        {
            //电脑随机走 ,其x与y都需要0~2的随机值。我们使用rand()%3就可以得到这个范围。这里使用row与col,解耦合。
            int x = rand()%row;
            int y = rand()%col;
            if(board[x][y] == ' ')
            {
                board[x][y] = '#';
                //只有当下棋了之后,结束循环
                break;
            }
        }
    }
    
    //判断局势
    // 返回*表示玩家获胜、返回#表示电脑获胜、返回C表示游戏继续、返回Q表示平局
    char isWin(char board[][COL],int row,int col)
    {
        int i,j;
        int flag = 1;
        //每一行或每一列、每个对角线判断后都需要将flag重置为1
    
        //如果有一个为空,就说明还不到获胜的点,所以如果为空,也返回flag=0
        //判断三行
        for(i=0 ; i0 ;j++,i--)
        {
            if( board[i][j] == ' ' || (board[i][j] != board[i-1][j+1]))
            {
                flag = 0;
            }
        }
        if(flag == 1){
            //这里出了循环,而且是右对角线,取右上角
            return board[col-1][0];
        }
    
        //到这里,说明没有出现胜利的。判断棋盘是否为空
        for(i=0 ; i
  • test.c 游戏测试

    //测试游戏逻辑
    
    #include "game.h"
    
    void menu()
    {
        printf("**------ GAME:三子棋 -------**\n");
        printf("**----- 输入1开始游戏 -------**\n");
        printf("**------- 输入0退出 --------**\n");
        printf("**-------------------------**\n");
    }
    
    void game()
    {
        //二维数组存储棋子。   ROW与COL是常量,定义在game.h头文件中
        char board[ROW][COL];
    
        //初始化棋盘,所有棋子为空格。
        InitBoard(board,ROW,COL);
    
        //打印棋盘:打印二维数组
        DisplayBoard(board,ROW,COL);
    
        char ret = 'C';
        if(rand()%5 == 0)
        {
            //如果这里是1,则电脑先下棋。
            //电脑下棋
            printf("电脑:这次我先走两步,给你一点难度!");
            computerMove(board,ROW,COL);
            computerMove(board,ROW,COL);
            //下棋后打印
            DisplayBoard(board,ROW,COL);
        }
        while (ret == 'C')
        {
    
            //玩家下棋
            playerMove(board,ROW,COL);
            //下棋后打印
            DisplayBoard(board,ROW,COL);
            //下棋后判断,是否玩家获胜
            ret = isWin(board,ROW,COL);
            if(ret == '*' || ret == 'Q')
            {
                break;
            }
            //电脑下棋
            computerMove(board,ROW,COL);
            //下棋后打印
            DisplayBoard(board,ROW,COL);
            //下棋后判断,是否电脑获胜
            ret = isWin(board,ROW,COL);
            if(ret == '#' || ret == 'Q')
            {
                break;
            }
        }
        if(ret == '*')
        {
            printf("YOU ARE WIN !!\n");
        }
        else if(ret == '#')
        {
            printf("电脑 WIN !!\n");
        }
        else
        {
            printf("~平局~1\n");
        }
    }
    
    int main()
    {
        int input = 0;
        //使用时间戳初始化种子,*5增大时间间隔
        srand((unsigned int)time(NULL) *5);
        do
        {
            menu();
            printf("请输入:");
            scanf("%d",&input);
            switch (input) {
                case 1:
                    printf("游戏开始。以行数、列数来指定下棋坐标,如1 1表示第一行第一列\n");
                    game();
                    break;
                case 0:
                    printf("已退出游戏");
                    break;
                default:
                    printf("输入有误,请重新输入!");
            }
        }while(input);
        return 0;
    }
    

数组的应用实例2:扫雷游戏

在此项目的实现中,遗留问题:
- 在其他扫雷游戏中,如果点击了一个点,这个点周围只要没有雷,会把这个坐标周围8个点没有雷的都展现出来。并且将这个点周围的八个点周围的雷数量扫出来,并显示在该点位置。并继续判断这8个点周围有没有雷(在这里注意,在判断八个点周围是不是雷的的时候,已经判断过的会被重复判断。我们要进行限制,判断过的不再判断),直到所有未知区域旁边已经挖开的点都存储的是雷的数量的时候,才停止。
  这就是在扫雷游戏中,如果点了一个点,就会展开一大片的原因。
  直到这一圈周围都有雷的时候就不会再展开
  思路:使用递归。
  
- 并且在其他扫雷中,如果你觉得这个地方是雷,可以右击鼠标进行标记。
  当选择坐标之后,提供选项,是挖雷还是将其标记为雷
  • game.h 游戏函数的声明

    #ifndef FIRST_GAME_H
    #define FIRST_GAME_H
    
    #include 
    #include 
    #include 
    
    //定义雷的数量
    #define NUM_MINE 10
    
    //虽然我们的数组大小是11*11的,但是我们在布置雷的时候,还是一个9*9的范围,这里这样定义更方便使用。
    #define ROW 9
    #define COL 9
    
    #define ROWS ROW+2
    #define COLS COL+2
    
    //声明初始化数组的函数声明
    void initBoard(char board[ROWS][COLS],int rows, int cols,char set);
    
    //声明打印数组的函数声明
    void printBoard(char board[ROWS][COLS],int row,int col);
    
    //布置雷函数声明
    void setMine(char board[ROWS][COLS],int row,int col);
    
    //排查雷
    void findMine(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col);
    
    #endif //FIRST_GAME_H
    
    
  • game.c 游戏函数的实现

    #include "game.h"
    
    //初始化数组 函数的实现
    void initBoard(char board[ROWS][COLS],int rows, int cols,char set)
    {
        int i,j;
        for(i=0 ; i=1 && x<=row && y>=1 && y<=col)
            {
                //如果坐标合法,就进行判断
                if(mine[x][y] == '1')
                {
                    printf("很遗憾,你挖到了雷,被炸死了呢(^_^) \n");
                    //打印雷数组
                    printBoard(mine,row,col);
                    //结束循环
                    break;
                }
                else
                {
                    //判断是不是已经挖开了
                    if(show[x][y] != '#')
                    {
                        printf("这里已经挖开了,重新挖!\n");
                        //如果已经挖开了就跳出本次循环。
                        continue;
                    }
                    //如果没有挖开,才进行判断
                    //如果不是雷,则统计周围有几个雷。因为雷是在mine数组中,传进入,以x,y为坐标点查找周围的雷
                    int count = mineCount(mine,x,y);
    
                    //放入show数组中。
                    //因为count是一个int类型变量,而这里我们要存储为char类型。
                    //在ASCII编码表中,'0'对应48,'1'对应49,'2'对应50,'3'对应51....
                    //所以我们只要将取来的count加上一个'0'就可以得到char类型数据
                    //如'3'对应51,'0'对应48。 3+'0' = 58,就是'3'
                    show[x][y] = count+'0';
    
                    //存入数组后,打印排查数组
                    printBoard(show,row,col);
    
                    //如果我们排出一个位置,则win+1。直到win =row*col - NUM_MINE时,就排完雷了
                    win++;
                }
            }
            else
            {
                printf("输入的坐标不合法,请重新输入。\n");
            }
        }
    
        //循环结束之后,判断win是不是row*col - NUM_MINE,如果是,则表示排雷成功,然后打印雷区。
        if(win == row*col - NUM_MINE)
        {
            printf("雷排完啦  Nice,You are Thor!!\n");
            //打印雷区
            printBoard(mine,row,col);
        }
    }
    
  • test.c 扫雷游戏的测试

    /*
     * 扫雷逻辑:点一个位置,以这个点为中心,周围的八个块中有几个雷,这个位置就显示数字几。
     * 第一步:布置雷
     *  - 创建一个9*9的二维数组,来存储布置的雷。比如随机创建了10个雷
     *  - 是雷的地方,存储字符'1';不是雷的地方,存储字符'0'
     *
     * 第二步:排查雷
     *  - 如果排查出了雷,那我们要放数字1。此时与存放雷的'1'就产生了冲突。
     *    此时,可以将存放的雷存储为*,不是雷的存储为#,排查出的雷存储为1。但是在打印的时候要一个一个判断,太麻烦了。
     *  - 我们可以在创建一个数组,其中专门存放排查出的信息,打印时只打印这个数组。
     *    比如点了一个位置,这个位置周围有两个雷,这个位置就存放2。
     *
     *  所以就是创建了两个数组:
     *  - 一个数组存储布置的雷; 一个数组存储排除出雷的信息。
     *  - 类型都是char,这样打印的时候以%c打印就可以了。
     *
     *  - 我们如果要扫四个角,那么可能会出现数组越界。
     *  - 所以我们定义存放排查信息的数组时,就可以定义大一点,9*9上下左右加一行。第二个数组就需要定义为11*11的二维数组
     *  - 为了更方便编写,我们可以将存放雷的数组也定义为11*11,这样就与另一个数组可以一一对应了。
     *    而实际上我们布置雷的时候,还是在中间布置,不会不知道外围的一圈。
     */
    
    #include "game.h"
    
    void menu()
    {
        printf("**------ GAME:扫 雷 -------**\n");
        printf("**----- 输入1开始游戏 -------**\n");
        printf("**------- 输入0退出 --------**\n");
        printf("**-------------------------**\n");
    }
    
    void game()
    {
        //定义数组,解耦合:将常量定义到头文件中。
        char mine[ROWS][COLS] = {0};  //存放布置的雷
        char show[ROWS][COLS] = {0};  //存放排查出雷的信息
    
        //初始化数组函数
        initBoard(mine,ROWS,COLS,'0');
        initBoard(show,ROWS,COLS,'#');
    
        //打印数组的函数。打印的时候我们只打印其中有雷的区域,没有的我们不打印。
        //打印show数组,让玩家来挖雷。
        printBoard(show,ROW,COL);
    
        //布置雷:只在下标为1~9的区域布置雷
        setMine(mine,ROW,COL);
        //给我们自己看的雷区,用于验证。
        //printBoard(mine,ROW,COL);
    
        //排查雷:传入两个数组,因为是在1~9的范围排雷,所以传ROW与COL
        findMine(mine,show,ROW,COL);
    }
    
    int main()
    {
        int input = 0;
        //使用时间戳初始化种子,*5增大时间间隔
        srand((unsigned int)time(NULL) *5);
        do
        {
            menu();
            printf("请输入:");
            scanf("%d",&input);
            switch (input) {
                case 1:
                    printf("扫雷吧,少年!!\n");
                    game();
                    break;
                case 0:
                    printf("已退出游戏");
                    break;
                default:
                    printf("输入有误,请重新输入!\n");
            }
        }while(input);
        return 0;
    }
    
    

数组练习

  • 逆序数组元素并打印

    #include 
    
    //
    void reverse(int arr[],int sz)
    {
        //起始下标
        int begin = 0;
        //结束下标
        int end = sz-1;
        //第一个和最后一个交换,然后第二个跟倒数第二个交换
        while(begin
  • 两个数组一样大,交换其中的元素。

    //交换两个数组中的元素
    
    int main()
    {
        int arr1[] ={1,3,5,7,9};
        int arr2[] ={2,4,6,8,10};
    
        int sz = sizeof(arr1)/sizeof(arr1[0]);
        int i;
        for(i=0 ; i
  • 编程实现,输入年份、月份,就可以输出这一年的这一个月有多少天

    //编程实现,输入年份、月份,就可以输出这一年的这一个月有多少天
    //闰年的2月是29天,其他年的2月是28天
    //
    #include 
    int main()
    {
        int year,month;
        //我们在最前面加一个0,这样是几月,下标为几,就对应这个月的天数。
        int days[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
        //如果读取正确,则进入循环
        printf("输入年份和月份:");
        while (scanf("%d %d",&year,&month) != EOF)
        {
            int day = days[month];
            if(year%4==0&&year%100!=0 || year%400 == 0)
            {
                if(month ==2)
                {
                    day++;
                }
            }
    
            printf("%d\n",day);
        }
    
        return 0;
    }
    
  • 在一个有序序列中插入数据,并且要求插入后还是有序的

    /*
     * 有一个有序数字序列,从小到大排列,将一个新输入的数据擦换如到序列中,保证插入新数后,序列仍然是升序。
     * 输入:
     * 第一行输入一个整数,0≤n≤50 ,也就是说最大是50个数。
     * 第二行输入n个升序牌系列的整数,输入用空格分割的n个整数。
     * 第三行输入要进行插入的一个整数。
     *
     * 输出,插入了数据后的有序排列的整数
     */
    
    #include 
    int main()
    {
        //序列最多是50个数,算上要插入的数据,应该是最多51个数,所以下标定义为50
        int arr[50] = {0};
    
        //整数序列
        int n;
        printf("多少个数的序列(0≤n≤50):");
        scanf("%d",&n);
        int i;
        printf("输入%d个数:",n);
        for(i=0 ; i=0 ; i--)
        {
            //如果当前元素比要插入的数大,则将当前元素放到后面的那个位置。
            //此时arr[i]所在位置就可以放别的元素了。每次循环的时候,这个位置都是为了放其他数字的。
            if(arr[i]>m)
            {
                arr[i+1] = arr[i];
                arr[i] = m;
            }
            else
            {
                //如果当前元素≤要插入的数,则将要插入的数放在这个数后面
                //arr[i+1] = m;//如果放在循环内,则话要考虑当插入的数被所有的的数都要小的这种情况。
                //放完之后,已经把数据插入了有序数列,就退出循环
                //break;
    
                //可以先跳出去,然后将要插入的数放在这个数后面。
                //这样就算要插入的数要比所有的数小,也可以插进去。
                break;
            }
        }
    
        //如果当前元素≤要插入的数,则将要插入的数放在这个数后面
        //如果要插入的数比所有的数都要小。也就是说i--之后i=-1了,跳出了循环
        //则说明要插入的数比所有的数都小。此时arr[-1+1] = arr[0] ,arr[0]=m,就插进去了。
        arr[i+1] = m;
    
        //打印
        printf("插入后:\n");
        for(i=0 ; i

你可能感兴趣的:(C语言,c++,c语言,后端,算法)