文章目录
- 第四章数组
- 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
通过输出结果得出结论:
-
一维数组在内存中是连续存放的。
-
随着数组下标的增长,元素的地址也在有规律地递增,地址由低到高变化。
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例(十一)