• C语言入门学习 --- 4.数组


    第四章数组

    1.一维数组的创建与初始化

    2.一维数组的使用

    3.一维数组在内存中的存储

    4.二维数组的创建与初始化

    5.二维数组的使用

    6.二维数组在内存中的存储

    7.数组越界

    8.数组作为函数参数

    9.数组应用例子1:五子棋

    10.数组应用例子2:扫雷游戏

    1.一维数组的创建与初始化。

    1.1一维数组的创建

    数组是一组相同类型元素的集合。

    一维数组的创建方式:

        //数组的元素类型 数组名 [常量表达式,用来表示数组的大小]
    
        //代码1
        int arr1[10];
    
        //代码2
        int count = 10;
        int arr2[count]; //不能正常创建
    
        //代码3
        char arr3[10];
        float arr4[20];
        double arr5[30];
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    注:代码2 C99语法支持,变长数组-数组得大小是变量。

    1.2一维数组的初始化

    数组的初始化是在创建数组的同时给数组的内容合理的初始值(初始化)。

      int arr1[5] = { 1,2,3,4,5 };
        int arr2[] = { 1,2,3 };
    
        char arr3[5] = { 'h','e','l','l','o' };
        char arr4[] = "hello";
    
    • 1
    • 2
    • 3
    • 4
    • 5

    数组在创建的时候不指定数组大小就要初始化。数组的元素大小根据元素的内容来确定。

    以下代码要区分,在内存中如何分配:

      char arr1[5] = "bit";  // b i t \0 \0
        char arr2[] = { 'b','i','t' };  //b i t \0
    
    • 1
    • 2
    1.3一维数组的使用
        #include 
    
      int main()
    {
        int arr[10] = { 0 };  //数组的不完全初始化,第一个内容为0,后面的内容默认也为0
        int i = 0;
        int sz = sizeof(arr) / sizeof(arr[0]);  //计算大小
        for (i = 0;i <= 9; i++)
        {
            printf("%d ", arr[i]);
        }
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    总结:

    • 1.数组是通过下标来访问,下标从0开始访问。

    • 2.数组的大小可以通过计算得到。

        int arr[10] = { 0 };
        int sz = sizeof(arr) / sizeof(arr[0]);
    
    • 1
    • 2
    1.4一维数组在内存中的存储
    #include 
    
    int main()
    {
        int arr[10] = { 0 };
        int sz = sizeof(arr) / sizeof(arr[0]);
        for (int i = 0; i < 10; i++)
        {
            printf("%p\n", &arr[i]);  //%p按地址的形式打印 - 十六进制
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    输出结果:006FFC04
    006FFC08
    006FFC0C
    006FFC10
    006FFC14
    006FFC18
    006FFC1C
    006FFC20
    006FFC24
    006FFC28

    通过输出结果得出结论:

    1. 一维数组在内存中是连续存放的。

    2. 随着数组下标的增长,元素的地址也在有规律地递增,地址由低到高变化。

    2.二维数组的创建与初始化

    2.1二维数组的创建
    //二维数组的创建
        char arr1[3][4];
        double arr2[3][5];
        int arr3[5][6];
    
    • 1
    • 2
    • 3
    • 4
    2.2二维数组的初始化
    //二维数组的初始化
        int arr4[1][2] = { 1,2 };
        int arr5[2][3] = { {1,5,6},{5,6,7} };
        int arr6[][2] = { 3,5 }; //行可以省略,列不可省略。
    
    • 1
    • 2
    • 3
    • 4
    2.3二维数组的使用

    二维数组的使用也是通过下标来进行。

    #include 
    
    int main()
    {
        int arr[3][2] = { {1,2},{3,4},{5,6} };
        int i = 0;
        int j = 0;
        for (i = 0; i < 3; i++)
        {
            for (j = 0; j < 2; j++)
            {
                printf("%d ", arr[i][j]);
            }
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.4二维数组在内存中的存储

    其实像一维数组一样。

    #include 
    
    int main()
    {
        int arr[3][2] = { {1,2},{3,4},{5,6} };
        int i = 0;
        int j = 0;
        for (i = 0; i < 3; i++)
        {
            for (j = 0; j < 2; j++)
            {
                printf("arr[%d][%d] = %p\n", i, j, &arr[i][j] );
            }
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    输出结果:
    通过分析结果,可以知道二维数组在内存中的存储也是连续存放的,位置也是从低到高。

    3.数组越界

    数组的下标有范围限制。

    数组的下标规定从0开始,如果数组有n个元素,最后一个元素下标为n-1。

    所以数组的下标小于0或者大于n-1,就是数组越界访问了,超过了数组合法空间的访问。

    C语言本身不做数组下标的越界检查,因此编译器不一定报错,但编译器不报错,不代表着程序就是正确的。

    因此写代码的时候,自己做好越界的检查。

    
    #include 
    
    int main()
    {
        int i = 0;
        int arr[3] = { 1,2,3 };
        for (i = 0;i < 4;i++)
        {
            printf("%d ",arr[i]); //当i=3时,越界访问了。
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4.数组作为函数参数

    在我们写代码的时候,往往有时需要将数组作为参数传入函数

    例:实现一个冒泡排序函数,将一个整型数组排序。

    4.1冒泡排序函数
    #include 
    
    void bubble_sort(int arr[], int s)
    {
        int x = 0;
        int y = 0;
        for (x = 0;x < s-1;x++)
        {
            for (y = 0;y < s-1-x; y++)
            {
                if (arr[y] > arr[y + 1])
                {
                    int tmp = 0;
                    tmp = arr[y];
                    arr[y] = arr[y + 1];
                    arr[y + 1] = tmp;
                }
            }
        }
    }
    
    int main()
    {
        int arr[5] = { 56,48,91,45,62 };
        int sz = sizeof(arr) / sizeof(arr[0]);
        int x = 0;
        bubble_sort(arr, sz);
        for (x = 0;x < sz;x++)
        {
            printf("%d ",arr[x]);
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    4.2数组名是什么?
    #include 
    
    int main()
    {
        int arr[] = { 1,2,3 };
        printf("%p\n",arr);
        printf("%p\n", &arr[0]);
        printf("%p\n", &arr);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    数组名是数组首元素的地址。(有两个例外)

    例外:

    1.sizeof(数组名),数据名表示整个数组,计算的是整个数组的大小单位为字节。

    2.&数组名,数组名表示整个数组,取出的是整个数组的地址。

    除了这两种情况以外,所有的数组名都表示数组首元素的地址。

    5.数组实例:

    5.1五子棋

    test.c - 测试游戏的逻辑

    game.c - 与游戏相关函数实现

    game.h - 与游戏相关函数的声明,符号声明,头文件的包含。

    //test.c
    #define _CRT_SECURE_NO_WARNINGS 1
    
    #include "game.h"
    
    void menu()  //打印菜单函数
    {
        printf("********************************\n");
        printf("*********   1.play    **********\n");
        printf("*********   0.exit    **********\n");
        printf("********************************\n");
    }
    
    
    void game()
    {
        char board[ROW][COL];
        char ret = 0;
        srand((unsigned int)time(NULL));
        InitBoard(board, ROW, COL);  //棋盘的初始化
        DisplayBoard(board, ROW, COL); //打印棋盘
        while (1)
        {
            PlayerMove(board, ROW, COL);  //玩家下棋
            DisplayBoard(board, ROW, COL); //显示当前棋盘状态
            ret = IsWin(board, ROW, COL);  //判断胜负
            if (ret != 'C') //如果是* # Q ,那么游戏就结束了。
            {
                break;
            }
    
            ComputerMove(board, ROW, COL);  //电脑下棋
            DisplayBoard(board, ROW, COL);    
            ret = IsWin(board, ROW, COL);
            if (ret != 'C')
            {
                break;
            }
        }
        if (ret == '*')
        {
            printf("玩家获胜\n");
        }
        else if (ret == '#')
        {
            printf("电脑获胜\n");
        }
        else
        {
            printf("平局\n");
        }
    
    }
    
    int main()
    {
        int input = 0;
        do
        {
            menu();
            printf("请选择:");
            scanf("%d", &input);
            switch (input)
            {
            case 1:
                game();
                break;
            case 0 :
                printf("退出游戏\n");
                break;
            default:
                printf("输入错误\n");
                break;
            }
        } while (input);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    //game.h
    #pragma once
    
    #define ROW 3
    #define COL 3
    
    #include 
    #include   //使用rand时需要调用
    #include      //使用time时需要调用
    
    void InitBoard(char board[ROW][COL], int row, int col);  //初始化函数的声明
    
    void DisplayBoard(char board[ROW][COL], int row, int col);  //显示棋盘状态函数的声明
    
    void PlayerMove(char board[ROW][COL], int row, int col);  //玩家下棋函数的声明
    
    void ComputerMove(char board[ROW][COL], int row, int col);  //电脑下棋函数的声明
    
    char IsWin(char board[ROW][COL], int row, int col);  //判断胜负函数的声明
    
    //  *  -   玩家获胜
    //  #  -   电脑获胜
    //  Q  -   平局
    //  C  -   继续
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    //game.c
    #define _CRT_SECURE_NO_WARNINGS 1
    
    #include "game.h"
    
    void InitBoard(char board[ROW][COL], int row, int col)  //初始化函数的定义
    {
        int i = 0;
        int j = 0;
        for (i = 0;i < row;i++)
        {
            for (j = 0;j < col;j++)
            {
                board[i][j] = ' ';
            }
        }
    }
    
    void DisplayBoard(char board[ROW][COL], int row, int col)  //显示棋盘状态函数的定义
    {
        int i = 0;
        int j = 0;
        for (i = 0;i < row;i++)
        {
            for (j = 0;j < col;j++)
            {
                printf(" %c ", board[i][j]);
                if (j < col - 1)
                {
                    printf("|");
                }
            }
            printf("\n");
            if (i < row - 1)
            {
                for (j = 0;j < col;j++)
                {
                    printf("---");
                    if (j < col - 1)
                    {
                        printf("|");
                    }
                }
                printf("\n");
            }
        }
    }
    
    void PlayerMove(char board[ROW][COL], int row, int col)  //玩家下棋函数的定义
    {
        int x = 0;
        int y = 0;
        printf("玩家走:\n");
        while (1)
        {
            printf("请选择你要走的坐标:");
            scanf("%d %d", &x, &y);
            if (x >= 1 && x <= row && y >= 1 && y <= col)
            {
                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)
        {
            int x = rand() % row;
            int y = rand() % col;
            if (board[x][y] == ' ')
            {
                board[x][y] = '#';
                break;
            }
        }
    }
    
    int IsFull(char board[ROW][COL], int row, int col)  //判断棋盘状态函数的定义
    {
        int i = 0;
        int j = 0;
        for (i = 0;i < row;i++)
        {
            for (j = 0;j < col;j++)
            {
                if (board[i][j] == ' ')
                    return 0;
            }
        }
        return 1;
    }
    
    char IsWin(char board[ROW][COL], int row, int col)  //判断胜负函数的定义
    {
        int x = 0;
        int y = 0;
    
        //三行
        for (x = 0;x < row;x++)
        {
            if (board[x][0] == board[x][1] && board[x][1] == board[x][2] && board[x][1] != ' ')
            {
                return board[x][1];
            }
        }
    
        //三列
        for (y = 0;y < col;y++)
        {
            if (board[0][y] == board[1][y] && board[1][y] == board[2][y] && board[1][y] != ' ')
            {
                return board[1][y];
            }
        }
    
        //右->左对角线
        if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
        {
            return board[1][1];
        }
    
        //左->右对角线
        if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
        {
            return board[1][1];
        }
    
        //判断棋盘是否满了
        //如果满了返回1,没满则返回0
        int ret = IsFull(board, ROW, COL);
        if (ret == 1)
        {
            return 'Q';
        }
        else
        {
            return 'C';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    5.2扫雷游戏

    test.c — 与游戏相关的逻辑测试

    game.c — 与游戏相关的函数实现

    game.h — 与游戏相关的函数的声明

    //test.c
    #define _CRT_SECURE_NO_WARNINGS 1
    
    #include "game.h"
    
    void menu()
    {
        printf("******************************\n");
        printf("**********1.play**************\n");
        printf("**********0.exit**************\n");
        printf("******************************\n");
    }
    
    void game()
    {
        char mine[ROWS][COLS] = { 0 };  //存放部署好的雷的信息
        char show[ROWS][COLS] = { 0 };  //存放排查出的雷的信息
    
        InitBoard(mine, ROWS, COLS, '0');  //雷盘初始化
        DisplayBoard(mine, ROW, COL);      //打印雷盘
    
        InitBoard(show, ROWS, COLS, '*');
        DisplayBoard(show, ROW, COL);
    
        Set_Mine(mine, ROW, COL);          //部署雷
        DisplayBoard(mine, ROW, COL);
    
        Find_Mine(mine, show, ROW, COL);   //排查雷
    }
    
    int main()
    {
        int input = 0;
        srand((unsigned int)time(NULL));
        do
        {
            menu(); //游戏菜单
            printf("请选择:");
            scanf("%d", &input);
            switch (input)
            {
            case 1:
                game(); //扫雷游戏
                break;
            case 0:
                printf("退出游戏\n");
                break;
            default:
                printf("输入错误,重新输入!\n");
            }
        } while (input);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    //game.c
    #define _CRT_SECURE_NO_WARNINGS 1
    
    #include "game.h"
    
    void InitBoard(char board[ROW][COL], int rows, int cols, char set)
    {
        int i = 0;
        int j = 0;
    
        for (i = 0;i < rows;i++)
        {
            for (j = 0;j < cols;j++)
            {
                board[i][j] = set;
            }
        }
    }
    
    void DisplayBoard(char board[ROW][COL], int row, int col)
    {
        int x = 0;
        int y = 0;
        printf("------ 扫雷游戏 -------\n");
        for (x = 0;x <= row;x++)
        {
            printf("%d ", x);
        }
        printf("\n");
        for (x = 1;x <= row;x++)
        {
            printf("%d ", x);
            for (y = 1;y <= col;y++)
            {
                printf("%c ",board[x][y]);
            }
            printf("\n");
        }
        printf("------ 扫雷游戏 -------\n");
    }
    static int get_mine_count(char mine[ROW][COL], int x, int y)
    {
        return mine[x-1][y] +
            mine[x-1][y-1] +
            mine[x][y-1] +
            mine[x+1][y-1] +
            mine[x+1][y] +
            mine[x+1][y+1] +
            mine[x][y+1] +
            mine[x-1][y-1] - 8 * '0';
    }
    
    void Set_Mine(char mine[ROWS][COLS], int row, int col)
    {
        int count = 10;
    
        while (count)
        {
            int x = rand() % row + 1;
            int y = rand() % col + 1;
            if (mine[x][y] == '0')
            {
                mine[x][y] = '1';
                count--;
            }
        }
    }
    
    void Find_Mine(char mine[ROW][COL], char show[ROW][COL], int row, int col)
    {
        int x = 0;
        int y = 0;
        int win = 0;
        while (win < row * col - Count)
        {
            printf("请输入选择的坐标:");
            scanf("%d %d", &x, &y);
            if (x >= 1 && x <= row && y >= 1 && y <= col)  //判断坐标的合理性
            {
                if (mine[x][y] == '1')
                {
                    printf("失败");
                    break;
                }
                else
                {
                    int count = get_mine_count(mine, x, y);  //不是雷的前提下,计算x,y坐标中周围有多少个雷
                    show[x][y] = count + '0';
                    DisplayBoard(show, ROW, COL);            //打印排查出的信息
                    win++;
                }
            }
            else
            {
                printf("错误,重新输入\n");
            }
        }
        if (win = row * col - Count)
        {
            printf("恭喜获胜\n");
        }
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    //game.h
    #pragma once
    
    #include 
    #include 
    #include 
    
    #define ROW 9
    #define COL 9
    
    #define ROWS ROW+2
    #define COLS COL+2
    
    #define Count 10
    
    //初始化函数声明
    void InitBoard(char board[ROW][COL], int rows, int cols, char set);
    
    //打印函数声明
    void DisplayBoard(char board[ROW][COL], int row, int col);
    
    //部署函数声明
    void Set_Mine(char mine[ROWS][COLS], int row, int col);
    
    //排查函数声明
    void Find_Mine(char mine[ROW][COL], char show[ROW][COL], int row, int col);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    上一章:C语言入门学习 — 3.函数

  • 相关阅读:
    训练自己的ChatGPT 语言模型(一).md
    Android 消息机制
    推荐莹莹API管理系统PHP源码
    USB2.0 UTMI+接口
    顺序表的操作
    rbf神经网络和bp神经网络,rbf神经网络是什么意思
    这套笔记可以解决90%以上的Java面试
    python模块之redisbloom redis布隆过滤器
    多聚体/壳聚糖修饰白蛋白纳米球/mPEG-HSA聚乙二醇人血清白蛋白纳米球的制备与研究
    openfeign技术学习与总结待续
  • 原文地址:https://blog.csdn.net/zhongziqia/article/details/136612264