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

文章目录

    • 第四章数组
      • 1.一维数组的创建与初始化。
        • 1.1一维数组的创建
        • 1.2一维数组的初始化
        • 1.3一维数组的使用
        • 1.4一维数组在内存中的存储
      • 2.二维数组的创建与初始化
        • 2.1二维数组的创建
        • 2.2二维数组的初始化
        • 2.3二维数组的使用
      • 2.4二维数组在内存中的存储
      • 3.数组越界
      • 4.数组作为函数参数
        • 4.1冒泡排序函数
        • 4.2数组名是什么?
      • 5.数组实例:
        • 5.1五子棋
        • 5.2扫雷游戏
      • 配套练习:

第四章数组

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

2.一维数组的使用

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

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

5.二维数组的使用

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

7.数组越界

8.数组作为函数参数

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

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

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

1.1一维数组的创建

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

一维数组的创建方式:

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

注:代码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";

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

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

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

总结:

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

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

    int arr[10] = { 0 };int sz = sizeof(arr) / sizeof(arr[0]);
1.4一维数组在内存中的存储
#include <stdio.h>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;
}

输出结果: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];
2.2二维数组的初始化
//二维数组的初始化int arr4[1][2] = { 1,2 };int arr5[2][3] = { {1,5,6},{5,6,7} };int arr6[][2] = { 3,5 }; //行可以省略,列不可省略。
2.3二维数组的使用

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

#include <stdio.h>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;
}

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

其实像一维数组一样。

#include <stdio.h>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;
}

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

3.数组越界

数组的下标有范围限制。

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

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

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

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


#include <stdio.h>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;
}

4.数组作为函数参数

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

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

4.1冒泡排序函数
#include <stdio.h>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;
}
4.2数组名是什么?
#include <stdio.h>int main()
{int arr[] = { 1,2,3 };printf("%p\n",arr);printf("%p\n", &arr[0]);printf("%p\n", &arr);return 0;
}

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

例外:

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;
}
//game.h
#pragma once#define ROW 3
#define COL 3#include <stdio.h>
#include <stdlib.h>  //使用rand时需要调用
#include <time.h>     //使用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  -   继续
//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,没满则返回0int ret = IsFull(board, ROW, COL);if (ret == 1){return 'Q';}else{return 'C';}
}
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);
}
//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");}
} 
//game.h
#pragma once#include <stdio.h>
#include <stdlib.h>
#include <time.h>#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);

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

配套练习:

C语言练习题110例(一)
C语言练习题110例(二)
C语言练习题110例(三)
C语言练习题110例(四)
C语言练习题110例(五)
C语言练习题110例(六)
C语言练习题110例(七)
C语言练习题110例(八)
C语言练习题110例(九)
C语言练习题110例(十)
C语言练习题110例(十一)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/743960.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AbilityStorage理解与反思

1.简介&#xff1a; AbilityStage是一个Module级别的组件容器&#xff0c;应用的HAP在首次加载时会创建一个AbilityStage实例&#xff0c;可以对该Module进行初始化等操作。 2.那么Module分为三类&#xff1a;Hap,Har,Hsp 官网上的表述容易误解&#xff1a;实际上AbilitySta…

表单修饰符和事件修饰符

表单修饰符和事件修饰符 表单修饰符 v-model.lazy v-model.lazy 失去焦点后再收集数据 <div id"app"><textarea name"" id"" cols"30" rows"10" v-model.lazy"a"></textarea>{{a}}<textar…

【深度学习】深度估计,Depth Anything Unleashing the Power of Large-Scale Unlabeled Data

论文标题&#xff1a;Depth Anything Unleashing the Power of Large-Scale Unlabeled Data 论文地址&#xff1a;https://arxiv.org/pdf/2401.10891.pdf 项目主页&#xff1a;https://depth-anything.github.io/ 演示地址&#xff1a;https://huggingface.co/spaces/LiheYoung…

PyCharm 中 Python 解释器的配置

温馨提示&#xff1a;本文 PyCharm 版本是 2022.3.3 前言 作为 Python 新手&#xff0c;在了解了基本语法之后&#xff0c;肯定得先用 IDE 工具写个 Hello World&#xff0c;来了解 Python 编程语法及 IDE 工具的常规配置和使用&#xff0c;这里我用的 IDE 工具是 PyCharm。 …

C++:构造函数赋初值的几种形式

构造函数用于类对象的初始化&#xff0c;没有返回值也不用写void&#xff0c;函数名与类名相同。构造函数可以有形参也可以无参&#xff0c;构造函数要写在类里边。语法&#xff1a;public: 类名(){ *** }。构造函数在创建对象&#xff08;实例化&#xff09;时会被调用且只有一…

leetcode第49题字母异位词分组

49. 字母异位词分组 给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 输入: strs ["eat", "tea", "tan", "ate", "na…

2024年服务器硬件知识普及篇(需要配置服务器的朋友可以参考)

嘿&#xff0c;大家好&#xff01;今天我们要聊一聊服务器硬件。无论你是想自己搭建一个服务器&#xff0c;还是对服务器硬件感兴趣&#xff0c;这篇文章都会对你有所帮助。我会尽量用简单易懂的语言&#xff0c;带你了解服务器硬件的基础知识。准备好了吗&#xff1f;让我们开…

unicloud update 修改

update 修改 使用腾讯云时更新方法必须搭配doc、where方法使用&#xff0c;db.collection(‘test’).update()会报如下错误&#xff1a;param should have required property ‘query’ collection.doc().update(Object data)未使用set、remove更新操作符的情况下&#xff0c…

odoo中_name_search用法

_name_search是Odoo中一个重要的方法&#xff0c;用于实现模型记录的搜索逻辑。这个方法通常在后端被调用&#xff0c;以便在Odoo的各种视图中&#xff08;如下拉列表选择框&#xff09;搜索和筛选记录。_name_search是模型中的一个API方法&#xff0c;可以被重写以自定义搜索逻…

一维数组_校门外的树

任务描述 某校大门外长度为L的马路上有一排树&#xff0c;每两棵相邻的树之间的间隔都是1米。我们可以把马路看成一个数轴&#xff0c;马路的一端在数轴0的位置&#xff0c;另一端在L的位置&#xff1b;数轴上的每个整数点&#xff0c;即0&#xff0c;1&#xff0c;2&#xff…

如何通过libusb直接向zebra打印机发送zpl,跨平台win/linux

环境&#xff1a;windows & linux & Zebra打印机gt820 windows: 之前安装了Zebra打印机官方驱动&#xff0c;所以先卸载掉驱动。再安装Zadig&#xff0c;用Zadig工具来安装WinUSB驱动。 zadig下载&#xff1a;Zadig - USB driver installation made easy 记住这两个数…

基金评价指标3——滚动收益率测算(近N日收益率,当周/月/年平均收益率)

文章目录 各个指标1. 近N日收益率2. 当周/月/年平均收益率 示例代码 各个指标 1. 近N日收益率 近N日收益率 (当日累计收益 - N日前的累计收益) / N日前的累计收益 2. 当周/月/年平均收益率 这里需要区分不同时间段的起始与终止区间 区间收益率 (区间终值累计收益 - 区间…

c语言指针基础下(下)

指针 字符指针变量 字符串变量的一般使用 int main() {char ch w;char* p &ch;*p h;printf("%c", ch);return 0; }上面就是通过指针的解引用改变了ch的值 int main() {char* p "ni hao a";//这个是常量字符串printf("%s\n", p);//打印…

超融合如何助力水务公司实现虚拟化与容器环境统一管理?

近些年&#xff0c;企业 IT 基础架构现代化转型的步伐逐渐加快&#xff0c;不少金融、医疗、政府等行业的用户&#xff0c;已在生产环境部署 Kubernetes 等云原生基础设施&#xff0c;为业务应用提供敏捷支持。不过&#xff0c;一些企业的容器化转型仍处于起步阶段&#xff0c;…

学习Android的第二十八天

目录 Android Service (服务) 线程 Service (服务) Service 相关方法 Android 非绑定 Service startService() 启动 Service 验证 startService() 启动 Service 的调用顺序 Android 绑定 Service bindService() 启动 Service 验证 BindService 启动 Service 的顺序 …

Instant --java学习笔记

Instant 时间线上的某个时刻 / 时间戳过获取lnstant的对象可以拿到此刻的时间&#xff0c;该时间由两部分组成:从1970-01-01 00:00:00 开始走到此刻的总秒数不够1秒的纳秒数 Instant的常见方法&#xff1a; Instant可以用来记录代码的执行时间&#xff0c;或用于记录用户操作某…

面试经验分享 | 通关某公司面试靶场

0x00:探测IP 首先打开时候长这个样&#xff0c;一开始感觉是迷惑行为&#xff0c;试了试/admin&#xff0c;/login这些发现都没有 随后F12查看网络&#xff0c;看到几个js文件带有传参&#xff0c;就丢sqlmap跑了一下无果 随后也反查了域名一下&#xff0c;发现没有域名&#…

[java入门到精通] 20 反射精讲

复习 1.索引&#xff1a;主要是提高查询性能。 2.索引分类&#xff1a;主键索引 唯一索引 普通索引 组合索引 全文索引 hash索引 3.索引底层数据结构是btree.非叶子结点是由&#xff1a;索引指针域 叶子结点&#xff1a;索引数据(数据地址)&#xff0c;是双链表 4.jdbc:java…

《高效便捷,探索快递柜系统架构的智慧之路》

随着电商业务的蓬勃发展&#xff0c;快递柜系统作为一种高效、便捷的最后一公里配送解决方案&#xff0c;正在受到越来越多企业和消费者的青睐。本篇博客将深入探讨快递柜系统的架构设计理念、优势和实践&#xff0c;帮助读者了解如何构建智能化的快递柜系统&#xff0c;提升物…

华为机试题-日志限流

题目 某软件系统会在运行过程中持续产生日志&#xff0c;系统每天运行 N 单位时间,运行期间每单位时间产生的日志条数保存在数组 records 中。records[i]表示第 i 单位时间内产生日志条数。由于系统磁盘空间限制,每天可记录保存的日志总数上限为 total 条。如果一天产生的日志总…