数组

讨论一个问题:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>

int main()
{
	char arr1[]= "abc";
	char arr2[]={'a','b','c'};
	printf("%d\n",sizeof(arr1));
	printf("%d\n",sizeof(arr2));
	printf("%d\n",strlen(arr1));
	printf("%d\n",strlen(arr2));
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.


这段代码运行的结果和我之前预料的有出入,运行之前预测输出:3,3,3,3运行的正确结果是:4,3,3,15.为什么会这样呢,首先arr1这种定义方式,我们会存储四个字节的内容:a,b,c,\0因此当我们使用sizeof的时候,会得出arr1占用的字节数4个字节。arr2定义后会存储3个字节的内容:a,b,c使用sizeof会算出占用3个字节。

此时我们用strlen,它的计算方式完全不同,他从第一个字符计数,遇到\0停下并且算出 \0之前有多少字符,对于arr1计算结果为3,对于arr2它不知何时才会碰到\0而停止计算,因为c后面的值我们不能确定,因此15实际上时随机值。

数组的使用

对于数组的使用我们之前介绍了一个操作符:[],下标引用操作符,它其实就是数组访问操作符。

  1. 数组时使用下标来访问的,下标是从0开始的
  2. 数组的大小可以通过计算得到

练习:输出打印一个整型数组各个元素的地址编号:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

int main()
{
	int arr[]= {1,2,3,4,5,6,7,8,9,10};
	int sz =sizeof(arr)/sizeof(arr[0]);
	int i = 0;
	for(i = 0; i<sz ;i++)
	{
		printf("&arr[%d] = %p\n",i,&arr[i]);
	}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

运行结果:

8.6C语言学习日志_数组


定义二维数组时,列一定不能省略,行可以省略。我们访问二维数组的时候行数和列数仍然是从0开始。

尝试定义并输出打印二维数组的所有元素:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

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

运行结果:

8.6C语言学习日志_数组_02

我们尝试打印输出二维数组每一个元素的地址:

8.6C语言学习日志_三子棋游戏_03

可以看到,二维数组本质上使用的内存空间依然是连续的一段线性存储空间。只是在我们假想的结构上是i行j列的。我们在实际运用的过程中完全可以将每一行作为一个一维数组来使用。

数组作为函数参数

我们将数组作为函数参数,写一个冒泡排序的函数,将给定的一个数组进行升序排序并输出:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>

void bubble_sort(int arr[],int sz)
{
	int temp = 0;
	int i = 0;
	//sz-1趟冒泡排序
	for(i = 0 ; i < sz-1;i++)
	{
		//每一趟的操作
		int j = 0;
		for(j = 0;j<sz-1-i; j++)
		{
			if(arr[j]>arr[j+1])
			{
				temp = arr[j];
				arr[j]= arr[j+1];
				arr[j+1] = temp;
			}
		}
	}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.

结果:

8.6C语言学习日志_数组_04

优化一下,如果已经有序了就提前跳出循环:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

void bubble_sort(int arr[],int sz)
{
	int temp = 0;
	int i = 0;
	int j = 0;
	int flag = 0;
	//sz-1趟冒泡排序
	for(i = 0 ; i < sz-1;i++)
	{
		//每一趟的操作
		int flag = 1;
		//flag =1我们让每一趟flag初始为1
		for(j = 0;j<sz-1-i; j++)
		{
			if(arr[j]>arr[j+1])
			{
				temp = arr[j];
				arr[j]= arr[j+1];
				arr[j+1] = temp;
				flag = 0;
				//一旦进行了交换,我们说这一趟之内仍未达成完全有序
			}
		}
		if(flag == 1)
		{
			break;
		}
		//一旦flag 为1了,就说明这个数组已经有序了,我们直接中途跳出循环
	}
}

int main()
{
	int arr[]={8,9,7,0,5,4,3,2,1,6};
	int i = 0;
	int sz = sizeof(arr)/sizeof(arr[0]);
	bubble_sort(arr,sz);
	for(i = 0;i <10;i++)
	{
		printf("%d ",arr[i]);
	}
}
  • 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.

需要再强调一下我们传参传入的数组,其实传入的是数组首元素的地址,本质上是一个指针,千万不要以为我们传入的是整个数组。

数组名一般时候都是代表的数组首元素的地址,本质是指针。但是!有两种例外的情况:

  1. sizeof(数组名)--此时的数组名代表整个数组,sizeof(数组名)计算的是整个数组的大小,单位是字节
  2. &数组名,数组名代表的是整个数组,&数组名,取出的是整个数组的地址。而数组的地址等于首元素的地址,二者的值是一样的但是意义完全不相同。


数组的实例应用

三子棋

这个三子棋的实现是我目前做的代码量最大的一个任务(流汗)。跟着老师的节奏,下来自己重新敲了一遍,感觉想不明白的还得反复看才勉强实现了需求,还是任重而道远。下面是代码:

头文件game.h

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
//宏定义
#define ROW 3
#define COL 3

void Init_Board(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);

//判断函数,需要反馈四种状态:继续('C')、玩家赢('*')、电脑赢('#')、平局('Q')
char IsWin(char board[ROW][COL],int row,int col);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.


源文件game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"

void Init_Board(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("|");
			}else{
				printf("\n");
			}
		}
		if(i<row-1)
		{
			for(j = 0;j<col;j++)
			{
				printf("---");
				if(j<col-1)
				{
					printf("|");
				}else
				{
					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)
{
	int x = 0;
	int y = 0;
	printf("电脑落棋:>\n");
	while(1)
	{
		x = rand()%row;
		y = rand()%col;
		if(board[x][y]==' ')
		{
			board[x][y]='#';
			break;
		}
	}
}

//判断棋盘是否满
//若满返回1
//若不满返回0
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 i = 0;
	int j = 0;
	//判断横三行
	for(i=0;i<row;i++)
	{
		if(board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1]!= ' ')
		{
			return board[i][0];
		}
	}
	//判断竖三列
	for(j=0;j<col;j++)
	{
		if(board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j]!= ' ')
		{
			return board[0][j];
		}
	}
	//判断两个对角线
	if(board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
	{
		return board[1][1];
	}
	if(board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
	{
		return board[0][0];
	}
	//判断是否平局
	if(1 == IsFull(board,ROW,COL))
	{
		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.


源文件test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
//测试三子棋游戏

//游戏的算法实现

void game()
{
	char ret = 0;
	char board[ROW][COL]={0};
	Init_Board(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')
		{
			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 if(ret == 'Q')
	{
		printf("平局\n");
	}
}


void menu()
{
	printf("*************************\n");
	printf("*** 1.paly    0.exit  ***\n");
	printf("*************************\n");
}

void test()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d",&input);
		switch(input)
		{
		case 1:
			printf("游戏开始\n");
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	
	}while(input);
}


int main()
{
	test();
	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.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.

最终实现的效果:有三种结局

第一种是玩家获胜:

8.6C语言学习日志_数组_05

第二种是电脑获胜:

8.6C语言学习日志_函数传参_06

第三种是平局:

8.6C语言学习日志_数组_07


扫雷游戏

明天在搞吧好累(流汗)