黑马程序员——c语言基础:二维数组

本文详细介绍了C语言中的二维数组,包括基本概念、定义、初始化、遍历和存储方式。通过实例展示了如何定义和初始化二维数组,以及如何遍历输出数组内容。此外,还探讨了二维数组在求平均分、寻找最大值和作为函数参数等方面的应用。最后,以一个简单的迷宫游戏为例,展示了如何使用二维数组控制角色移动。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.二维数组的基本概念和使用


 二维数组:可以看做是一个特殊的一维数组,这个数组的每个元素又是一个一维数组。


 二维数组的定义:

    类型说明符 数组名[常量表达式1][常量表达式2]

    其中常量表达式1代表第一维下标长度,常量表达式2表示第二维下标长度。

    例如:int a[3][4]; // 说明了一个三行四列的数组,数组名为a,其下标变量的类型为整形。该数组的下标变量共有3*4个。


 二维数组的初始化:

 1.定义的同时初始化

    1.1完全初始化

        1.1.1将二维数组当做元素类型是数组的特殊一维数组:int a[2][3] = {{1,2,3}, {4,5,6}};

        1.1.2连续赋值:int a[2][3] = {1,2,3,4,5,6};

        1.1.3可以省略第一维:int a[][3] = {{1,2,3}, {4,5,6}}; int a[][3] = {1,2,3,4,5,6};

 

    1.2部分初始化

        int a[3][4] = {1};

        int a[3][4] = {{1}, {2}, {3}}; // 这种写法第一维长度可以省略

        int a[3][4] = {1,2,3,4,5};

 2.先定义,后初始化

    int a[3][4];

    a[0][0] = 1;


 二维数组的遍历:通过下标访问二维数组中的每一个元素。

 

 二维数组的存储方式:

  1.计算机会给二维数组分配一块连续的存储空间。

2.数组名代表数组的首地址,从首地址位置依次放入第1行、第二行……

3.每一行的存储方式:从行首地址开始,依次存储该行的第1个元素、第2个元素、第3个元素……

  4.每个元素占用相同的字节数(取决于数组类型)

  5.数组中元素之间的地址是连续的


实例:定义初始化一个二维数组,并遍历输出数组内容。

#include <stdio.h>


int main(int argc, const char * argv[]) {

    // 定义并初始化一个二维数组

    int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};

    

    // 用双重for循环打印出二维数组中每一个元素

    for (int i = 0; i <3; i ++) { // 第一维有3个元素

        for (int j = 0; j < 4; j ++) { // 第二维有4个元素

            printf("%d\t", a[i][j]);

        }

        // 换行

        printf("\n");

    }

    

    return 0;

}



2.二维数组的应用实例


1)一个学习小组有5个人,每个人有三门课的考试成绩。求每门课程的平均分和三门课的平均分。

#include <stdio.h>


int main(int argc, const char * argv[]) {

    

    // 定义并初始化数组

    int score[5][3] = {

        {80,75,92},

        {61,65,71},

        {59,63,70},

        {85,87,90},

        {76,77,85}

    };

    // 定义变量

    float sum = 0; // 每门课程的总分

    float avgSum = 0; // 三门课程平均分的总分

    

    printf("每门课程的平均均分分别为:"); // 打印提示

    

    // 每门课程的平均分

    for (int i = 0; i < 3; i ++) { // 三门课程

        for (int j = 0; j < 5; j ++) { // 5个人

            sum += score[i][j]; // 累加每人的分数

        }

        // 输出每门课程的平均分

        printf("%.2f,", sum / 5);

        // 累加每科的平均分

        avgSum += sum/5.0;

        // 接下来要计算下一科成绩,把sum0

        sum = 0;

    }

    

    // 输出三门课的平均分

    printf("\n三门课程的平均分为:%.2f", avgSum / 3);

    return 0;

}


2)有一个5*3的矩阵,要求编程序以求出其中值最大的那个元素的值及其所在的行号和列号。

#include <stdio.h>


int main(int argc, const char * argv[]) {

    // 定义并初始化数组

    int a[5][3] = {

        {80,75,92},

        {61,65,71},

        {59,63,70},

        {85,87,90},

        {76,77,85}

    };

    

    // 定义变量

    int max = a[0][0]; // 用于存储数组中的最大值

    int hang = 0; // 用于存储最大元素的行号

    int lie = 0; // 用于存储最大元素的列号

    

    // 找出最大值及其所在行号和列号

    for (int i =0; i < 5; i ++) { // 5

        for (int j = 0; j < 3; j ++) { // 3

            // 如果当前元素大于max

            if (a[i][j] > max) {

                max = a[i][j]; // 将当前元素的值赋值给max

                hang = i; // 将当前行号赋值给hang

                lie = j; // 将当前列赋值给lie

            }

        }

    }

    

    // 输出最大值及其行号和列号

    printf("该矩阵中的最大元素为:%d,其所在行号为%d,所在列号为%d.", max, hang, lie);

    

    return 0;

}


3.二维数组做为函数的参数


  3.1二维数组元素作为函数参数:相当于变量的值传递过程。

  3.2二维数组名作为函数参数:相当于地址传递。

注意事项:

1)类型和长度要一致。当实参数组维数大于形参数组时,形参数组只取实参数组的一部分,其余部分不起作用。

2)二维数组作为函数的形参,可以不写第一维的长度。


二维数组作为函数参数的实例:

 从键盘上接收两个参数分别存放到m,n中,使用m,n构成数组:

 1)定义一个函数使用i * j 初始化 a[i][j];

 2)定义一个函数打印二维数组的每一个值


#include <stdio.h>


// 定义函数,初始化数组

void initArray(int m, int n, int arr[m][n]){

    for (int i = 0; i < m; i ++) {

        for (int j = 0; j < n; j ++ ) {

            arr[i][j] = i *j;

        }

    }

}


// 定义函数,打印二维数组的每一个值

void printArray(int m, int n, int arr[m][n]){

    for (int i = 0; i < m; i ++) {

        for (int j = 0; j < n; j ++) {

            printf("%d\t", arr[i][j]);

        }

        printf("\n");

    }

}

int main(int argc, const char * argv[]) {

    // 定义变量

    int m; int n;

    // 提示用户输入两个参数

    printf("请输入两个参数(“,”隔开)");

    // 接收参数

    scanf("%d,%d", &m, &n);

    // 定义数组

    int arr[m][n];

    

    // 初始化数组

    initArray(m, n, arr);

    

    // 输出数组元素

    printArray(m, n, arr);

    

    return 0;

}


4.应用:迷宫游戏

玩家通过键盘录入w(上),s(下),a(左),d(右)控制小人向不同方向移动,当小人移动到出口位置,玩家胜利。

#include <stdio.h>

#define ROW 7

#define COL 7




// 打印地图

void printMap(char map[ROW][COL]){

    for (int i = 0; i < ROW; i ++) {

        for (int j = 0; j < COL; j ++) {

            printf("%c", map[i][j]);

        }

        printf("\n");

    }


}


// 实现小人的移动

void personMove(char map[ROW][COL], int oldX, int oldY, int newX, int newY){

    char temp;

    temp = map[oldX][oldY];

    map[oldX][oldY] = map[newX][newY];

    map[newX][newY] = temp;

    

}


int main(int argc, const char * argv[]) {

    //************* 定义变量 ***************

    //1.定义变量用于存储地图、用户输入的方向、小人当前位置

    // 定义变量保存地图

    char map[ROW][COL] = {

        {'#','#','#','#','#','#','#',},

        {'#','o','#',' ',' ',' ',' ',},

        {'#',' ','#',' ','#','#','#',},

        {'#',' ','#',' ',' ',' ','#',},

        {'#',' ','#','#','#',' ','#',},

        {'#',' ',' ',' ',' ',' ','#',},

        {'#','#','#','#','#','#','#',}

    };

    

    // 定义变量保存用户输入的方向

    char direction;

    

    // 定义变量保存小人当前位置

    int currentX = 1;

    int currentY = 1;

    

    //2.先打印一遍地图

    printMap(map);

    //3.提示用户游戏玩法

    printf("请控制小人移动:w. s. a. d.  q.退出\n");

    //************* 进行循环控制 ***************

    while (1) {

        //4.接收用户输入的方向

        scanf("%c", &direction);

        getchar(); // 吸收多余的\n

        //5.判断用户输入了什么方向

        switch (direction) {

            case 'w':

            case 'W':

                //************* 判断小人是否移动 ***************

                //6.判断小人是否能够移动

                //核心:要知道小人的下一个位置是否是路

                if (map[currentX - 1][currentY] == ' ') { // 如果小人的下个位置是路(即空格)

                    // 让小人开始移动,移动的核心:小人和路交换

                    personMove(map, currentX, currentY, currentX - 1, currentY);

                    // 重新记录小人当前的位置

                    currentX = currentX -1;

                }

                //不是路:什么也不干

                break;

                

            case 's':

            case 'S':

                //************* 判断小人是否移动 ***************

                //6.判断小人是否能够移动

                //核心:要知道小人的下一个位置是否是路

                if (map[currentX + 1][currentY] == ' ') { // 如果小人的下个位置是路(即空格)

                    // 让小人开始移动,移动的核心:小人和路交换

                    personMove(map, currentX, currentY, currentX + 1, currentY);

                    

                    // 重新记录小人当前的位置

                    currentX = currentX +1;

                }

                //不是路:什么也不干

                

                break;

                

            case 'a':

            case 'A':

                //************* 判断小人是否移动 ***************

                //6.判断小人是否能够移动

                //核心:要知道小人的下一个位置是否是路

                if (map[currentX][currentY -1] == ' ') { // 如果小人的下个位置是路(即空格)

                    // 让小人开始移动,移动的核心:小人和路交换

                    personMove(map, currentX, currentY, currentX, currentY - 1);


                    // 重新记录小人当前的位置

                    currentY --;

                }

                //不是路:什么也不干

                

                break;

                

            case 'd':

            case 'D':

                //************* 判断小人是否移动 ***************

                //6.判断小人是否能够移动

                //核心:要知道小人的下一个位置是否是路

                if (map[currentX][currentY +1] == ' ') { // 如果小人的下个位置是路(即空格)

                    // 让小人开始移动,移动的核心:小人和路交换

                    personMove(map, currentX, currentY, currentX, currentY + 1);

                    

                    // 重新记录小人当前的位置

                    currentY = currentY +1;

                }

                //不是路:什么也不干

                

                break;

                

            case 'q':

            case 'Q':

                return 0;

                break;

                

            default:

                break;

        }

        

        //7.重绘地图

        printMap(map);

        

        //************* 判断小人是否走出迷宫 ***************

        

        if (currentY == COL -1) { // 判断y的值是否等于列数-1

            //是:提示走出迷宫

            printf("恭喜你,走出了迷宫。\n");

            //break;游戏结束

            break;

        }

        

    }

    return 0;

}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值