C语言从入门到精通 第七章(利用数组处理批量数据)

一、数组概述

(1)所谓数组,就是一个集合,里面按顺序存放了相同类型的数据元素。

(2)数组中的每个数据元素都是相同的数据类型。

(3)数组是由连续的内存位置组成的。

二、一维数组

1、一维数组的定义

一维数组是由具有一个下标的数组元素组成的数组,其定义形式如下:

<数据类型> <数组名>[<数组长度>];

(1)数据类型是类型说明符,数组名是数组的名字,数组长度是任一值为正整数的int型常量表达式,用来指定数组中元素的个数,即数组的大小。

(2)数组元素的下标是从0到(数组长度-1)。

(3)数组名的命名规范与变量名命名规范一致,不要和变量重名。

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
	//代码1
	int arr1[10];    //arr1的类型:int [10]
	//代码2
	int count = 10;
	//int arr2[count];
	//代码3
	char arr3[10];    //arr3的类型:char [10]
	float arr4[1];    //arr4的类型:float [10]
	double arr5[20];    //arr5的类型:double [10]

	return 0;
}

2、一维数组的初始化

与所有的基本数据类型相同,数组也可以在定义时初始化,有两种形式:

(1)指定数组长度,花括号中各项数据之间以逗号分隔,若花括号内的元素个数小于(只能小于等于,如果大于将会报错)数组长度,则剩下的数组元素默认为零(或者说空)。

<数据类型> <数组名>[ <数组长度> ] = { <值1>, <值2> ...};

(2)不指定数组长度,花括号中各项数据之间以逗号分隔,数组长度即花括号内的元素个数。

<数据类型> <数组名>[ ] = { <值1>, <值2> ...};

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
	int arr1[10] = { 1,2,3 };    //10个元素
	int arr2[] = { 1,2,3,4 };    //4个元素
	int arr3[5] = { 1,2,3,4,5 }; //5个元素
	char arr4[3] = { 'a',98, 'c' };   //3个元素
	char arr5[] = { 'a','b','c' };    //3个元素
	char arr6[] = "abcdef";      //7个元素,还有一个'\0'在最后面

	return 0;
}

3、访问数组元素的语法形式

<数组名>[<表达式>]

(1)表达式是非负的int型表达式,称为下标,下标用于指定所要访问的数组中元素的位置,在C++中"[]"是一个运算符,称为下标运算符。

(2)数组下标从0开始,长度为n的数组,其下标的范围是0到n-1。(下标超出范围会造成越界访问,不管会不会报错,程序都是会存在问题的)

|------|----------|----------|----------|-----|----------|
| 数组元素 | 数组a第1个元素 | 数组a第2个元素 | 数组a第3个元素 | ... | 数组a第n个元素 |
| 访问方式 | a[0] | a[1] | a[2] | ... | a[n-1] |
| 元素值 | <值1> | <值2> | <值3> | ... | <值n> |

(3)在数组定义以后,给数组元素赋值时,必须一个元素一个元素地逐个访问。

(4)数组名是常量,不可以对其进行赋值,但可对其元素进行赋值。

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
	int arr[10] = { 0 };   //数组的不完全初始化
	//计算数组的元素个数
	int sz = sizeof(arr) / sizeof(arr[0]);
	//对数组内容赋值,数组是使用下标来访问的,下标从0开始
	int i = 0;  //i做下标
	for (i = 0; i < 10; i++)
	{
		arr[i] = i;
	}
	//输出数组的内容
	for (i = 0; i < 10; ++i)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

4、一维数组在内存中的存储

一维数组在内存中是连续存放的,随着下标的增加,地址由低到高。

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
	int arr[10] = { 0 };
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);

	for (i = 0; i < sz; ++i)
	{
		printf("&arr[%d] = %p\n", i, &arr[i]);    //数组在内存中是连续存放的,随着下标的增加,地址由低到高
	}

	return 0;
}

二、二维数组

1、二维数组的定义

二维数组是以行和列(即二维)形式排列的固定数目元素的集合,并且组成数组的每个元素的类型都相同,即带有两个下标的数组。定义二维数组的语法是:

<数据类型> <数组名>[<表达式1>][<表达式2>];

(1)数据类型是类型说明符,数组名是数组的名字,数组名的命名规范与变量名命名规范一致,不要和变量重名。

(2)两个表达式都是值为正整数的常量表达式,分别用来指定数组中行和列的数目。

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
	//数组创建
	int arr[3][4];       //相当于创建一个3行4列的矩阵
	char arr[3][5];
	double arr[2][4];

	return 0;
}

2、二维数组的初始化

与一维数组相同,二维数组也可以在定义时初始化,有三种形式:

(1)指定数组的行数和列数,在同一行中的元素可以用花括号括起来,并用逗号分隔,这种方式最为直观,推荐使用。

<数据类型> <数组名>[ <行数> ][ <列数> ] = { {<数据1>, <数据2> } , {<数据3>, <数据4> } };

(2)指定数组的行数和列数,初始化列表中的数据按顺序从二维数组的第一行第一列开始逐行赋值。

<数据类型> <数组名>[ <行数> ][ <列数> ] = { <数据1>, <数据2>, <数据3>, <数据4>};

(3)仅指定数组的列数(无论如何列数都不能省略),程序会根据初始化列表的元素个数推断出二维数组的行数,然后从二维数组的第一行第一列开始逐行赋值。

<数据类型> <数组名>[ ][ <列数> ] = { <数据1>, <数据2>, <数据3>, <数据4>};

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
	//数组初始化
	int arr[3][4] = { 1,2,3,4 };
	int arr[3][4] = { {1,2},{4,5} };  //二维数组可理解为一维数组的数组
	int arr[][4] = { {2,3},{4,5} };   //二维数组如果有初始化,行数可以省略,列数不能省略

	return 0;
}

3、访问数组元素的语法形式

<数组名>[<表达式1>][<表达式2>]

(1)两个表达式是非负整数的表达式。

(2)表达式1指定行下标,表达式2指定列下标。

(3)二维数组可以看做一个**++++元素类型为一维数组++++** 的一维数组 ,有r个元素(r为行数),其中每个一维数组的长度均为l(l为列数),一维数组下标从0开始,其下标的范围是0到l-1 。(对于二维数组a[r][l],"a[x]"的语意是把二维数组的第x+1行元素当作一维数组,"a[x]"可视作该一维数组的名称

|--------------|--------------------------------|--------------------------------|-----|----------------------------|
| 一维数组a[0] | a[0][0] = <数据1> | a[0][1] = <数据2> | ... | a[0][l-1] = <数据l> |
| 一维数组a[1] | a[1][0] = <数据l+1> | a[1][1] = <数据l+2> | ... | a[1][l-1] = <数据2l> |
| 一维数组a[2] | a[2][0] = <数据2l+1> | a[2][1] = <数据2l+2> | ... | a[2][l-1] = <数据3l> |
| ... | ... | ... | ... | ... |
| 一维数组a[r-1] | a[r-1][0] = <数据(r-1)l+1> | a[r-1][1] = <数据(r-1)l+2> | ... | a[r-1][l-1] = <数据rl> |

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
	int arr[3][4] = { 0 };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 4; j++)
		{
			arr[i][j] = i * 4 + j;
		}
	}
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 4; j++)
		{
			printf("%d ", arr[i][j]);
		}
	}

	return 0;
}

4、二维数组在内存中的存储

二维数组在内存中也是连续存放的,从第一行第一列开始,随着下标的增加,地址由低到高,第一行的元素完毕后,转向第二行第一列的元素,以此类推。

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
	int arr[3][4];
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 4; j++)
		{
			printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);  //二维数组在内存中也是连续存储的
		}
	}

	return 0;
}

三、字符数组

1、char类型的一维数组

(1)char类型的一维数组的存储结构如下所示(实际存储的是字符对应的ASCII码):

|--------|--------|--------|--------|--------|--------|-----|----------|
| a[0] | a[1] | a[2] | a[3] | a[4] | a[5] | ... | a[n-1] |
| '字符1' | '字符2' | '字符3' | '字符4' | '字符5' | '字符6' | ... | '字符n-1' |

(2)字符串以空字符结尾(系统在处理字符串常量存储时会自动加一个 ' \0 '),而字符数组可以不含空字符。

(3)字符串可以存储在一维字符数组内,比如:

char word[10] = "Hello"; //存储该字符串至少需要6个char存储空间,因为要算上'\0'

(4)由双引号括起来的字符串常量具有静态字符串数组类型,换句话说,字符串常量也可视作一个字符数组。

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
	//使用字符串初始化字符数组
	char str[] = "Hello World";  //字符串名后面要加中括号[];等号后面要用双引号包含字符串

	//按一般方式初始化字符数组
	char char_group[] = { 'H','e','l','l','o',' ','W','o','r','l','d','\0','1' };  //'\0'是字符串结束标志

	//以字符串形式输出(遇到'\0'即认为字符串结束,将会停止输出该字符串)
	printf("%s\n", str);
	printf("%s\n", char_group);

	return 0;
}

2、字符数组的输入输出

(1)字符数组的输入输出可以有两种方法:

①借助循环用格式符"%c"将逐个字符输入输出。

②用格式符"%s"将整个字符串一次输入或输出,输入时遇到空格表示输入结束,输出时遇结束符 ' \0 ' 就停止输出。(格式符"%s"需对应字符数组的首元素的地址)

(2)举例:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>

int main()
{
	//将整个字符串一口气输入
	char str[100];   //预留足够的空间存储输入的字符串
	scanf("%s", str);  //str是字符数组首元素的地址,不用加"&",往后会详细解释

	//字符逐一输入
	char char_group[100];  //预留足够的空间存储输入的字符串
	int i = 0;
	while (i < 100)
	{
		//scanf("%c", &(char_group[i]));   这种方式显然很不合适!
		i++;
	}

	//以字符串形式输出(遇到'\0'即认为字符串结束,将会停止输出该字符串)
	printf("%s\n", str);
	//printf("%s\n", char_group);

	//字符逐一输出
	i = 0;
	while (i < 100)
	{
		//printf("%c", str[i]);
		//printf("%c", char_group[i]);   这种方式显然很浪费算力!
		i++;
	}

	return 0;
}

3、字符串处理函数

(1)使用字符串处理函数需要添加头文件string.h。

(2)puts函数------输出字符串的函数:

①作用:将一个字符串输出到终端,以'\0'为结束标志。

②示例:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
	char str[] = "114514";
	puts(str);

	return 0;
}

(3)gets函数------输入字符串的函数:

①作用:从终端输入一个字符串到字符数组,并且得到一个函数值,这个函数值是字符数组的起始地址。

②示例:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>

int main()
{
	char str[100];
	gets(str);
	puts(str);

	return 0;
}

(4)stract函数------字符串连接函数:

①作用:参数为两个字符数组首元素的地址,把第二个字符数组接在第一个字符数组后面,结果放在第一个字符数组中,并返回第一个字符数组的地址。

②示例:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>

int main()
{
	char str1[10] = "Hello";
	char str2[10] = "鼠标";
	printf("%s\n", strcat(str1, str2));
	printf("%s\n", str1);

	return 0;
}

(5)strcpy和strncpy函数------字符串复制函数:

①作用:参数为两个字符数组首元素的地址,将第二个字符串复制到第一个字符串中(第一个字符数组的容量必须足够大,至少不应小于第二个字符数组,且第一个参数必须写成数组名形式,第二个参数可以是数组名也可以是一个字符串常量)。

②示例:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>

int main()
{
	char str1[10] = "Hello";
	char str2[10] = "鼠标";
	strcpy(str1, str2);
	printf("%s\n", str1);

	return 0;
}

(6)strcmp------字符串比较函数:

①作用:参数为两个字符数组首元素的地址,如两个数组全部字符相同,则认为两个字符串相同,返回0;如两个数组出现不同字符,则以第一对不相同的字符的比较结果为准,至于比较规则个人认为意义不大,如果结果为第一个字符串大于第二个字符串则返回一个正整数,果结果为第一个字符串小于第二个字符串则返回一个负整数。

②示例:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>

int main()
{
	char str1[10] = "Hello";
	char str2[10] = "hello";
	char str3[10] = "HEllo";
	printf("%d\n", strcmp(str1, str2));
	printf("%d\n", strcmp(str1, str3));
	printf("%d\n", strcmp(str2, str3));

	return 0;
}

(7)strlen函数------测字符串长度的函数:

①作用:返回一个字符串的实际长度,以 ' \0 ' 作为结束标志,但结束标志不算在字符串的长度内

②示例:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string>

int main()
{
	"acdfdsg";
	"";   //空字符串

	char arr1[] = "abc";
	printf("%s\n", arr1);
	char arr2[] = { 'a','b','c' };
	printf("%s\n", arr2);
	char arr3[] = { 'a','b','c','\0' }; 
	printf("%s\n", arr3);
	printf("arr1字符串的长度为:%d\n", strlen(arr1));
	printf("arr2字符串的长度为:%d\n", strlen(arr2));   //"\0"的位置不清楚,字符串不知何时结束,长度为随机值
	printf("arr3字符串的长度为:%d\n", strlen(arr3));

	return 0;
}

(8)strlwr函数------转换为小写的函数:

①作用:将一个字符串中的大写字母转换为小写字母。

②示例:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>

int main()
{
	char str1[10] = "Hello";
	strlwr(str1);
	printf("%s\n", str1);

	return 0;
}

(9)strupr函数------转换为大写的函数:

①作用:将一个字符串中的小写字母转换为大写字母。

②示例:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>

int main()
{
	char str1[10] = "Hello";
	strupr(str1);
	printf("%s\n", str1);

	return 0;
}

四、越界访问与数组名的作用

1、越界访问

以一维数组为例,数组的下规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1,数组的下标如果小于0,或者大于n-1,就是数组越界访问,超出了数组合法空间的访问。(二维数组的行和列也可能存在越界,多维数组同理)

cpp 复制代码
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	for (i = 0; i <= 10; i++)
	{
		printf("%d\n", arr[i]);//当i等于10的时候,越界访问了
	}
	return 0;
}

2、数组名的作用

(1) 以下 两种情况外,所有的数组名都表示数组首元素的地址

①sizeof(数组名)------计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组。

②&数组名------取出的是数组的地址(++++数组的地址和数组首元素地址相同,但是二者并不等价,这点在指针运算中会有所体现++++)。

(2)二维数组视为一维数组的数组 ,那么二维数组的数组名表示的首元素的地址其实是一个一维数组的地址(第一行的地址)。

(3)数组作为函数的参数时,实际传递的就是数组首元素的地址。(关于函数在下一章会详细介绍)

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

void bubble_sort(int arr[] ,int len)
{
	int i = 0;
	for (i = 0; i < len - 1; i++)
	{
		int j = 0;
		for (j = 0; j < len - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
}
int main()
{
	int arr[] = { 3,1,7,5,8,9,0,2,4,6 };   //需要使用冒泡排序将其变为有序数组
	int len = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, len);   //数组名的本质是数组首元素的地址,形参中的arr本质上其实是指针变量
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

五、应用数组设计的两个小游戏

1、三子棋人机对战

(1)main.cpp:

cpp 复制代码
#include"game.h"

void menu()
{
	printf("***********************************\n");
	printf("***** 1. 开始游戏  0.退出游戏 *****\n");
	printf("***********************************\n");
	printf("请输入1或0进行选择:\n");
}
void game()
{
	system("cls");
	char board[ROW][COL] = { 0 };
	InitBoard(board, ROW, COL);
	bool ret = false;
	while (!ret)
	{
		PrintBoard(board, ROW, COL);
		PlayerMove(board, ROW, COL);
		PrintBoard(board, ROW, COL);
		ret = Determine(board, ROW, COL);
		if (ret)
			break;
		ComputerMove(board, ROW, COL);
		PrintBoard(board, ROW, COL);
		ret = Determine(board, ROW, COL);
		if (ret)
			break;
		system("pause");
		system("cls");
	}
	system("pause");
	system("cls");
}

int main()
{
	srand((unsigned)time(NULL));
	int choice ;
	do
	{
		menu();
		scanf("%d", &choice);
		switch (choice)
		{
		case 1:    //开始游戏
			game();
			break;
		case 0:    //退出游戏
			break;
		default:
		{
			printf("输入有误,请重新输入!\n");
			system("pause");
			system("cls");
			break;
		}   
		}
	} while (choice);
	
	system("pause");

	return 0;
}

(2)game.h:

cpp 复制代码
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 3
#define COL 3
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

void InitBoard(char board[ROW][COL], int row, int col);    //初始化棋盘

void PrintBoard(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); //电脑下棋

bool Determine(char board[ROW][COL], int row, int col);    //判断输赢

(3)game.cpp:

cpp 复制代码
#include"game.h"

void InitBoard(char board[ROW][COL], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}
}

void PrintBoard(char board[ROW][COL], int row, int col)
{
	int i = 0, j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (j == col - 1)
			{
				printf(" %c \n", board[i][j]);
				break;
			}
			printf(" %c |", board[i][j]);
		}
		if (i == row - 1)
		{
			break;
		}
		for (j = 0; j < col; j++)
		{
			if (j == col - 1)
			{
				printf("---\n");
				break;
			}
			printf("---|");
		}
	}
}

void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0, y = 0;
	printf("请玩家输入坐标:");
	do
	{
		scanf("%d %d", &x, &y);
		if ((x<1 || y<1 || x>row || y>col) || (board[x - 1][y - 1] != ' '))
		{
			printf("输入无效坐标,请重新输入:");
		}
		else
		{
			break;
		}
	} while (true);
	board[x - 1][y - 1] = '*';
	printf("玩家下棋:\n");
}

void ComputerMove(char board[ROW][COL], int row, int col)
{
	int x = 0, y = 0;
	do
	{
		x = rand() % row + 1;    //非智能随机生成
		y = rand() % col + 1;
		if (board[x - 1][y - 1] == ' ')
		{
			board[x - 1][y - 1] = '#';
			break;
		}
	} while (true);
	printf("电脑下棋:\n");
}

bool Determine(char board[ROW][COL], int row, int col)
{
	int i = 0, j = 0, a = 0, b = 0, c = 0;
	//玩家赢
	for (i = 1; i < row; i++)
	{
		for (j = 1; j < col; j++)
		{
			if (board[i][j] == '*'&&board[i - 1][j - 1] == '*')  //斜线判断
			{
				a++;
			}
			if (j == col - 1)
			{
				if (a == col - 1)
				{
					printf("玩家胜利,本局游戏结束!\n");
					return true;
				}
				else
				{
					a = 0;
				}
			}
		}
	}
	for (i = 0; i < row; i++)
	{
		for (j = 1; j < col; j++)
		{
			if (board[i][j] == '*'&&board[i][j - 1] == '*')  //横线判断
			{
				b++;
			}
			if (j == col - 1)
			{
				if (b == col - 1)
				{
					printf("玩家胜利,本局游戏结束!\n");
					return true;
				}
				else
				{
					b = 0;
				}
			}
		}
	}
	for (j = 0; j < col; j++)
	{
		for (i = 1; i < row; i++)
		{
			if (board[i][j] == '*'&&board[i - 1][j] == '*')  //竖线判断
			{
				c++;
			}
			if (i == row - 1)
			{
				if (c == row - 1)
				{
					printf("玩家胜利,本局游戏结束!\n");
					return true;
				}
				else
				{
					c = 0;
				}
			}
		}
	}

	//电脑赢
	for (i = 1; i < row; i++)
	{
		for (j = 1; j < col; j++)
		{
			if (board[i][j] == '#'&&board[i - 1][j - 1] == '#')  //斜线判断
			{
				a++;
			}
			if (j == col - 1)
			{
				if (a == col - 1)
				{
					printf("电脑胜利,本局游戏结束!\n");
					return true;
				}
				else
				{
					a = 0;
				}
			}
		}
	}
	for (i = 0; i < row; i++)
	{
		for (j = 1; j < col; j++)
		{
			if (board[i][j] == '#'&&board[i][j - 1] == '#')  //横线判断
			{
				b++;
			}
			if (j == col - 1)
			{
				if (b == col - 1)
				{
					printf("电脑胜利,本局游戏结束!\n");
					return true;
				}
				else
				{
					b = 0;
				}
			}
		}
	}
	for (j = 0; j < col; j++)
	{
		for (i = 1; i < row; i++)
		{
			if (board[i][j] == '#'&&board[i - 1][j] == '#')  //竖线判断
			{
				c++;
			}
			if (i == row - 1)
			{
				if (c == row - 1)
				{
					printf("电脑胜利,本局游戏结束!\n");
					return true;
				}
				else
				{
					c = 0;
				}
			}
		}
	}

	//和棋
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
				goto FLAG;    //跳出两层循环
		}
	}
FLAG:
	if (i == row && j == col)
	{
		printf("和棋,本局游戏结束!\n");
		return true;
	}
	return false;   //游戏不结束则继续进行
}

2、扫雷

(1)main.cpp:

cpp 复制代码
#include "game.h"

void menu()
{
	printf("************************************\n");
	printf("******* 1.开始游戏 0.退出游戏 ******\n");
	printf("************************************\n");
}

void game()
{
	char mine[ROWS][COLS] = { 0 };   //存放布雷情况
	char show[ROWS][COLS] = { 0 };   //存放排雷情况

	InitBoard(mine, ROWS, COLS, '0');   //在没有布雷的时候,全部格子视为0
	InitBoard(show, ROWS, COLS, '*');   //没有排雷的格子全部标为*
	SetMine(mine, ROW, COL);            //随机生成雷

	while (true)
	{
		system("cls");
		printf("当前情况:\n");
		DisplayBoard(mine, ROW, COL);  //用于测试
		printf("\n");
		DisplayBoard(show, ROW, COL);
		bool ret = FineMine(mine, show, ROW, COL);
		if (ret)
		{
			break;
		}
		int count = 0;
		for (int i = 1; i <= ROW; i++)
		{
			for (int j = 1; j <= COL; j++)
			{
				if (show[i][j] == '*')
					count++;
			}
		}
		if (count == EASY_COUNT)
		{
			printf("成功找出所有雷!游戏结束!\n");
			break;
		}
	}
	//该参考没有添加标记地雷功能
}

int main()
{
	srand((unsigned)time(NULL));
	int choice;
	do
	{
		system("cls");
		menu();
		printf("请输入1或0进行选择:");
		scanf("%d", &choice);
		switch (choice)
		{
		case 1:
			game();
			break;
		case 0:
			break;
		default:
			printf("输入有误,请重新输入!");
			break;
		}
		system("pause");
	} while (choice);

	system("pause");

	return 0;
}

(2)game.h:

cpp 复制代码
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10
#include <stdio.h>
#include <time.h>
#include <stdlib.h>

void InitBoard(char board[ROWS][COLS], int rows, int cols, char c);

void DisplayBoard(char board[ROWS][COLS], int row, int col);

void SetMine(char board[ROWS][COLS], int row, int col);

bool FineMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

void AddMine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols);
void AddMine1(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y);
void AddMine2(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y);
void AddMine3(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y);
void AddMine4(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y);

(3)game.cpp:

cpp 复制代码
#include "game.h"

void InitBoard(char board[ROWS][COLS], int rows, int cols, char c)
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			board[i][j] = c;
		}
	}
}

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	for (int i = 1; i <= row; i++)
	{
		for (int j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}

void SetMine(char board[ROWS][COLS], int row, int col)
{
	int x, y, count = 0;
	while (count < EASY_COUNT)
	{
		x = rand() % row + 1;
		y = rand() % col + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count++;
		}
	}
}

bool FineMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x, y;
	while (true)
	{
		printf("请输入需要排查的坐标:");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				system("cls");
				for (int i = 1; i <= row; i++)
				{
					for (int j = 1; j <= col; j++)
					{
						if (mine[i][j] != '1')
							printf("%c ", show[i][j]);
						else
							printf("& ");
					}
					printf("\n");
				}
				printf("很遗憾,你踩到地雷了,游戏结束......\n");
				return true;
			}
			if (show[x][y] != '*')
			{
				printf("该坐标已被排查,请重新选择!\n");
			}
			else if (mine[x][y] == '0')
			{
				AddMine(mine, show, x, y);
				system("cls");
				DisplayBoard(mine, ROW, COL);   //用于测试
				printf("\n");
				DisplayBoard(show, ROW, COL);
				return false;
			}
		}
		else
		{
			printf("输入无效坐标,请重新输入!\n");
		}
		system("pause");
	}
}

void AddMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	char deter = mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1]
		+ mine[x][y - 1] + mine[x][y + 1] + mine[x + 1][y - 1]
		+ mine[x + 1][y] + mine[x + 1][y + 1] - 7 * '0';
	if (deter == '0' && x >= 1 && x <= ROW && y >= 1 && y <= COL)
	{
		AddMine1(mine, show, x - 1, y);
		AddMine2(mine, show, x + 1, y);
		AddMine3(mine, show, x, y - 1);
		AddMine4(mine, show, x, y + 1);
	}
	show[x][y] = deter;
}
void AddMine1(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	char deter = mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1]
		+ mine[x][y - 1] + mine[x][y + 1] + mine[x + 1][y - 1]
		+ mine[x + 1][y] + mine[x + 1][y + 1] - 7 * '0';
	if (deter == '0' && x >= 1 && x <= ROW && y >= 1 && y <= COL)
	{
		AddMine1(mine, show, x - 1, y);
		AddMine3(mine, show, x, y - 1);
		AddMine4(mine, show, x, y + 1);
	}
	show[x][y] = deter;
}
void AddMine2(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	char deter = mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1]
		+ mine[x][y - 1] + mine[x][y + 1] + mine[x + 1][y - 1]
		+ mine[x + 1][y] + mine[x + 1][y + 1] - 7 * '0';
	if (deter == '0' && x >= 1 && x <= ROW && y >= 1 && y <= COL)
	{
		AddMine2(mine, show, x + 1, y);
		AddMine3(mine, show, x, y - 1);
		AddMine4(mine, show, x, y + 1);
	}
	show[x][y] = deter;
}
void AddMine3(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	char deter = mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1]
		+ mine[x][y - 1] + mine[x][y + 1] + mine[x + 1][y - 1]
		+ mine[x + 1][y] + mine[x + 1][y + 1] - 7 * '0';
	if (deter == '0' && x >= 1 && x <= ROW && y >= 1 && y <= COL)
	{
		AddMine3(mine, show, x, y - 1);
	}
	show[x][y] = deter;
}
void AddMine4(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	char deter = mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1]
		+ mine[x][y - 1] + mine[x][y + 1] + mine[x + 1][y - 1]
		+ mine[x + 1][y] + mine[x + 1][y + 1] - 7 * '0';
	if (deter == '0' && x >= 1 && x <= ROW && y >= 1 && y <= COL)
	{
		AddMine4(mine, show, x, y + 1);
	}
	show[x][y] = deter;
}
相关推荐
დ旧言~6 分钟前
【高阶数据结构】图论
算法·深度优先·广度优先·宽度优先·推荐算法
时光の尘6 分钟前
C语言菜鸟入门·关键字·float以及double的用法
运维·服务器·c语言·开发语言·stm32·单片机·c
张彦峰ZYF11 分钟前
投资策略规划最优决策分析
分布式·算法·金融
-一杯为品-15 分钟前
【51单片机】程序实验5&6.独立按键-矩阵按键
c语言·笔记·学习·51单片机·硬件工程
The_Ticker26 分钟前
CFD平台如何接入实时行情源
java·大数据·数据库·人工智能·算法·区块链·软件工程
爪哇学长1 小时前
双指针算法详解:原理、应用场景及代码示例
java·数据结构·算法
爱摸鱼的孔乙己1 小时前
【数据结构】链表(leetcode)
c语言·数据结构·c++·链表·csdn
Dola_Pan1 小时前
C语言:数组转换指针的时机
c语言·开发语言·算法
繁依Fanyi1 小时前
简易安卓句分器实现
java·服务器·开发语言·算法·eclipse
烦躁的大鼻嘎2 小时前
模拟算法实例讲解:从理论到实践的编程之旅
数据结构·c++·算法·leetcode