C语言初阶——4数组

1.一维数组

1.1的创建和初始化。

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

1.1.1 创建数组

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

在这里插入图片描述

注意:

  1. [4]中的4是可以省略的.数组的长度就和后面初始化的列表里的元素个数一致~~
  2. [4]如果不省略的时候,后面的初始化列表的元素不能比4个多~~
  3. [4]如果不省略的时候, ,后面的初始化列表的元素可以比4个少的时候,就把数组剩下的元素填成0.
  4. 创建数组的时候, []里面的数字只能是一个常量, 不能是变量(在C89中)
  5. 如果省略[4] 中的数字,就必须使用{ }初始化~~
  6. 如果没有省略[4],并且也没有初始化~会显示一个随机值,这个值是VS自己填充的(16进制下是0xcc,翻译成中文是“烫烫烫”)0XCC:是CPU的一个特殊指令——int3中断指令.为了防止数组越界,设置的一个固定值
    在这里插入图片描述
    如果将int arr[4]放在main函数外面,这个数组就表示是一个全局变量了

在这里插入图片描述
如果是一个全局变量,没有被显式初始化,会被自动初始化为0.
如果是一个局部变量,没有被显式初始化,就是.上次残留的值~~

只要创建变量都应该显式初始化~~

1.1.2 数组初始化

数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值(初始化)。针对字符数组初始化,可以像普通数组一样来使用{ }进行初始化,也可以使用“ ”用一个字符串。

char str1[] = { 'a','b','c' };
	char str2[] = { 'a',98,'c' };
	char str2[] = "abc";//注意:写双引号的时候,就是字符串,多了一个‘\0’
//不是每个字符数组都可以称为“字符串”
//字符串是一种特殊的字符数组,一定是以'\0'结尾(“ ”)!


strlen(str1);//这是一个未定义行为,!!!因为不是所有数组都是字符串数组,只有字符串数组结尾才是‘\0’,才能这么求长度
	

不是每个字符数组都可以称为“字符串”,字符串是一种特殊的字符数组,一定是以’\0’结尾(“ ”)!

给任何str系列的函数(比如strlen, strcmp…)进行传参的时候,必须要由人来保证参数是一个合法的字符串~

1.2 一维数组的使用

数组的使用:

  1. 求数组长度:sizeof(arr)/siziof(arr[0])
  2. 取下标 :[ ]
    0开始,到len-1结束
    10 [ 0, 9] 一旦数组下标越界,就是未定义行为!!
#include<stdio.h>

//创建数组

int main()
{
	int arr[10] = { 0 };
	//以循环的方式,给这个数组设置一个值,从1到10
	for (int i = 0; i < 10; i++)
	{
		arr[i] = i + 1;
	}
	for (int i = 0; i < 10; i++)
	{
		printf("%d\n", arr[i]);
	}
	return 0;
}

在这里插入图片描述

1.3 一维数组在内存中的存储

#include<stdio.h>

//数组在内存中的存储

int main()
{
	char arr[10] = { 0 };
	for (int i = 0; i < 10; i++)
	{
		printf("%p\n", &arr[i]);
	}

	return 0;
}

在这里插入图片描述
数组中的元素处在连续的内存空间上~~

2. 二维数组

二维数组本质上也是一维数组,只不过每个元素又是一个一维数组,所谓的数组,可以理解成一种特殊的类型,int arr[4];可以理解成是创建了4个int 类型的变量,也可以理解成创建了一个变量arr,其类型是int [4]

啥叫三维数组?
本质上也是一个-维数组, 只不过每个元素又是一个二 维数组~~
啥叫四维数组?
不管是几维数组,本质都是一维数组. 操作/语法都是和一维数组一 样的

2.1 二维数组的创建和初始化

在这里插入图片描述
如何看,可以借助VS编译器来看

1.第一种

#include<stdio.h>

//数组在内存中的存储




int main()
{
	//二维数组
	int arr[3][4] = { 0 };
	printf("啦啦啦");

	return 0;
}

在这里插入图片描述
在这里插入图片描述

2.第二种

#include<stdio.h>

//数组在内存中的存储




int main()
{
	//二维数组
	int arr[3][4] = { 0 };
	int arr1[3][4] = { 1,2,3,4,5 };
	printf("啦啦啦");

	return 0;
}

在这里插入图片描述

3.第三种

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

	};

{1,2,0,0}
{3,4,0,0}
{5,0,0,0}

4.第四种

int arr4[3][4] = {
		(1,2),
		(3,4),
		(5)
	};

这里的(1,2)涉及到逗号表达式
逗号表达式:a,b, C =>的值就是c,即最后一个逗号后面的值.
所以这种二维数组初始化内容为:
{2,4,5,0}
{0,0,0,0}
{0,0,0,0}

5.第五种


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

前面的可以省略
这个数组初始化为{1,2,3,0}
针对二维数组,列数一定要存在,不能省略,对于三维、四维、五维,都是只有第一个方括号可以省略不写,其他均不能省略

2.2. 二维数组的使用

#include<stdio.h>

//二维数组的使用

int  main()
{
	int arr[3][4] = {
		2,4,5
	};

	for (int row = 0; row < 3; row++)
	{
		// arr[row]  这个操作相当于取出其中的某一行,这一行也是一个数组
		for (int col = 0; col < 4; col++)
		{
			printf("%d ", arr[row][col]);//这里会先去取第一个下标,然后再取第二个下标
		}
		printf("\n");
	}

	return 0;
}

在这里插入图片描述

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

像一维数组一样,这里我们尝试打印二维数组的每个元素。它也和一维数组一样是顺序存储的

#include<stdio.h>

//数组在内存中的存储

int  main()
{
	int arr[3][4] = {
		2,4,5
	};

	for (int row = 0; row < 3; row++)
	{
		// arr[row]  这个操作相当于取出其中的某一行,这一行也是一个数组
		for (int col = 0; col < 4; col++)
		{
			printf("%p ", &arr[row][col]);//这里会先去取第一个下标,然后再取第二个下标
		}
		printf("\n");
	}

	return 0;
}

在这里插入图片描述

3. 数组作为函数参数

C语言中的第二个惊天BUG:数组名变成指针
数组名作为函数的参数也会触发转成指针的操作.在函数内部是无法直接求数组的长度的.必须要在函数外面提前把长度求好,再以参数的形式传给函数内部

3.1 实现冒泡排序

冒泡排序的核心思路,比较两个相邻元素的大小,看看是不是符合排序的要求.(例如,要求进行升序排序,就看前一个元素是不是比后一个元素小)如果不符合排序要求,就进行交换~
从前往后遍历,每次取出一个最大的元素放到数组最后了;从后往前遍历,每次取出一个最小的元素放到数组最前了~~

#include<stdio.h>

//冒泡排序
int bubbleSort(int arr[], int size)
{
	//写一个从后往前遍历的版本,
	//每次从后往前遍历比较相邻元素,每一趟比较把最小的元素放在最前面

	//bound => 边界的意思,使用这个变量的值,表示已排序区间和待排序区间的分界线
	//[0,bound ) 表示已排序区间
	//[bound,size)表示待排序区间
	int bound = 0;
	for (; bound < size; bound++)
	{
		//通过这个循环,来及控制后续比较相邻元素的比较趟数
		//接下来实现一趟比较交换的过程
		for (int cur = size - 1; cur > bound;cur --)//size-1表示最后一个元素的下标。可以通过arr[size-1]来获取到最后一个元素
		{//进行比较  
		//相邻元素就是以cur为基准
			//cur - 1 , cur + 1;
			//由于我们现在cur 是从 size -1 开始的 所以我们不能使用cur +1,cur+1的话可能数组下标越界,产生未定义行为
			 //所以我们使用cur -1来表示相邻元素
			if (arr[cur - 1] > arr[cur])
			{//不符合升序条件,就进行交换
				int tem = arr[cur - 1];
				arr[cur - 1] = arr[cur];
				arr[cur] = tem;
			
			}
		}
	}


}



int main()
{

	int arr[] = { 2,5,1,6,7,8,10 };
	int size = sizeof(arr) / sizeof(arr[0]);
	bubbleSort(arr, size);
	for (int i = 0; i < size; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}


写代码的过程中,经常会遇到这类问题:
到底是+1还是-1 ,还是不加不减,到底是<还是<=。"差一问题"实际开发中,非常容易出错的问题。也是测试_工程师在设计测试用例的时候,重点关注的地方。解决思路:把边界值具体代入数值,推演程序是否符合要求

自己写的代码

在这里插入代码片//自己实现一下冒泡排序~先实现一下老师讲课版本(从前往后遍历)
int bubble(int arr[], int size)
{//从后往前遍历

	int bound = 0;
	for (; bound < size; bound++)
	{
		for (int cur = size - 1; cur > bound; cur--)
		{
			if (arr[cur - 1] > arr[cur]) {
			
				int tem = arr[cur - 1];
				arr[cur - 1] = arr[cur ];
				arr[cur] = tem;
			}
		}
	}

}

再写一个从前往后遍历版本;

int bubble2(int arr[], int size)
{
	int bound = size-1;

	for (; bound > 0; bound--)
	{
		for (int cur = 0; cur <= bound; cur++)
		{
			if (arr[cur]  < arr[cur+1])
			{
				int tem = arr[cur ];
				arr[cur ] = arr[cur+1];
				arr[cur+1] = tem;
			}
		}
	}
	return 0;
}

4. 数组的应用实例1:三子棋

在这里插入图片描述

只要连成一条线就赢了。

  1. 我们先表示棋盘:创建一个 3*3的二维数组,每个元素是一个char类型,'x’表示玩家1、'o’表示玩家2、'空格’表示空白。
  2. 游戏流程:
    (1)创建棋盘,并初始化~把所有位置都设为空格
    (2)打印棋盘
    (3)玩家进行落子,让玩家来输入一组坐标(row,col),进行落子
    (4)判定是否获胜
    (5)电脑进行落子~ 随机落子

先想清楚,程序该咋写,再动手,然后写成上面这种条理性的描述,然后在动手敲代码

//课堂代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
//三子棋

#define MAX_ROW 3
#define MAX_COL 3


//这里的 3 称为 magic  number 魔幻数字~~不建议直接写进去!建议创建两个宏

void init(char chess[MAX_ROW][MAX_COL]) {
	for (int row = 0; row < MAX_ROW; row++) {
		for (int col = 0; col < MAX_COL; col++) {
			chess[row][col] = ' ';
		}
	}
}

void print(char chess[MAX_ROW][MAX_COL]) {
	printf("+---+---+---+\n");
	for (int row = 0; row < MAX_ROW; row++) {
		printf("|");
		for (int col = 0; col < MAX_COL; col++) {
			printf(" %c |", chess[row][col]);
		}
		printf("\n+---+---+---+\n");

	}
}

void playerMove(char chess[MAX_ROW][MAX_COL]) {
	printf("玩家落子......\n");
	while (1)
	{
		printf("请输入 坐标(row col):");
		int row = 0;
		int col = 0;
		scanf("%d %d", &row, &col);
		//进行合法性校验,判定用户输入的内容是否合法
		//如果不合法,就让用户重新输入
		if (row < 0 || row >= MAX_ROW|| col < 0 || col >= MAX_COL){
	    //不合法,就让用户重新输入
		printf("您的输入有误!请重新输入!\n");
	       continue;//结束本次循环,进行下一次循环
	    }
	// 假设用户输入了 1, 1 但是 1, 1 位置已经有子了
	   if (chess[row][col] != ' ') {
		printf("您输入的位置已经有棋了!请重新输入!\n");
		continue;
	   }
	   //进行落子
	   chess[row][col] = 'x';
	   break;
	}
}
void computerMove(char chess[MAX_ROW][MAX_COL]) {
	while (1) {
		int row = rand() % MAX_ROW; //结果是 0 1 2
		int col = rand() % MAX_COL;
		if (chess[row][col] != ' ') {
			//说明这个位置已经有子了
			continue;
		}
		chess[row][col] = 'o';
		break;
	}
}


//返回 1 表示满了,返回 0 表示未满
int isFull(char chess[MAX_ROW][MAX_COL]) {
	//遍历棋盘,看有没有空格,如果有,则棋盘未满
	for (int row = 0; row < MAX_ROW; row++) {
		for (int col = 0; col < MAX_COL; col++) {
			if (chess[row][col] == ' ') {
				return 0;
			}
		}
	}
	return 1;
}







//此处函数给一个char 返回值 我们约定
// 如果返回 x 表示玩家 获胜
// 如果返回 o 表示玩家 获胜
// 如果返回 ' ' 表示胜负未分,还要继续下棋
// 如果返回 p  ,表示平局
char isGameOver(char chess[MAX_ROW][MAX_COL]) {
	//扫描所有的行,所有的列,以及两个对角线
	//(1)扫描所有的行,
	for (int row = 0; row < MAX_ROW; row++) {
		if (chess[row][0] != ' '
			&& chess[row][0] == chess[row][1]
			&& chess[row][0] == chess[row][2])
		{
			return chess[row][0];//return chess[row][1];
			//return chess[row][2]; 均可,这三个是等价的
		}
	}
	//(2)扫描所有列
	for (int col = 0; col < MAX_COL; col++) {
		if (chess[0][col] != ' '
			&& chess[0][col] == chess[1][col]
			&& chess[0][col] == chess[2][col])
		{
			return chess[0][col];//return chess[row][1];
			//return chess[row][2]; 均可,这三个是等价的
		}
	}
	// (3) 扫描两个对角线
	if (chess[0][0] != ' '
		&& chess[0][0] == chess[1][1]
		&& chess[0][0] == chess [2][2]) {
		return chess[0][0];
	}
	if (chess[0][2] != ' '
		&& chess[0][2] == chess[1][1]
		&& chess[0][2] == chess[2][0]) {
		return chess[0][2];
	}
	//判定是否和棋
	if (isFull(chess)) {
		printf("p");
	}
	
	
	//胜负未分
	return ' ';

}



int  main()
{
	//不建议使用全局变量,最好使用局部变量
	char chessBoard[MAX_ROW][MAX_COL];
	// 1. 对棋盘进行初始化
	init(chessBoard);
	char winner = isGameOver(chessBoard);
	while (1)
	{
		// 2. 打印棋盘
		print(chessBoard);
		// 3. 玩家落子
		playerMove(chessBoard);
		// 4.判定胜负
	    
		
		if (winner != ' ') {
			//游戏结束
			break;
		}
		// 5. 电脑落子
		computerMove(chessBoard);

		// 6.判定胜负

		char winner = isGameOver(chessBoard);
		if (winner != ' ') {
			//游戏结束
			break;
		}

	}
	if (winner == 'x')
	{
		printf("玩家方获胜!恭喜你赢了\n");
	}
	else if (winner == 'o') {
		printf("电脑方获胜!你咋连人工智障都下不过!\n");
	}
	else {
		printf("和棋了!你和人工智障五五开\n");
	}
	// 7. 打印棋盘
	print(chessBoard);
	return 0;
}

5. 数组的应用实例2:扫雷游戏

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值