数组初阶-1

系列文章目录

第一章 如何学习好C语言
第二章 C语言的编译工具的相关问题
第三章 对C语言的初步认识
第四章 C语言的初阶学习
第五章 C语言的高阶学习
第六章 C语言有关的小项目
第七章 C语言的思维导图及重要知识思维导图

第四章 C语言的初阶学习–数组

一、一维数组的创建,初始化,使用

1.1一维数组的创建形式

数组:一组相同类型的元素的集合
格式:type_t arr_name [const_n];
type_t 指数组的元素类型,const_n是一个常量表达式,用来指定数组的大小,arr_name 数组名
在C99的标准之前,数组的大小必须是常量或者常量表达式
在C99之后,数组的大小可以是变量,为了支持变长数组(但对编译器有所要求)

1.2一维数组的初始化

int a[10]={1,2,3}; //不完全初始化。
int a[]={1,2,3,4,5}; //数组的大小未说明时,由元素的个数决定。
注意区别:
char ch1[10]={‘a’,’b’,’c’};初始化放了三个元素,其余七个补0
char ch2[10]=”abc”; 初始化放了a,b,c,\0.补了6个0,字符串里面是含’\0’的
在这里插入图片描述

1.3一维数组的使用

操作符:[],下标引用操作符,它是用于数组访问的操作符。
例1:如何将数组的所有元素进行打印

#define _CRT_SECURE_NO_WARNINGS 1 
#include <stdio.h>
int main()
{
	//一维数组的使用,[]下标引用符
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };     //未指定数组的大小
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);     //计算数组的长度
	//打印数组的每个元素,正序
	/*for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}*/
	//倒序,关键就在于使用下标
	for (i = sz-1; i >=0; i--)
	{
		printf("%d ", arr[i]);   
	}
	return 0;
}

小结:
1.数组是使用下标来访问的,下标是从0开始的。
2.没有给定数组的长度时候:借助int sz=sizeof(arr)/sizeof(arr[0]); 进行求解
这个求解方法也可以用于尽可能防止数组越界。

1.4一维数组在内存中的布局情况

#include <stdio.h>
int main()
{
	//一维数组的使用,[]下标引用符
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };     //未指定数组的大小
	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;
}

在这里插入图片描述
在这里插入图片描述
不难发现,一维数组在内存中存储是连续的。

二、二维数组的创建,初始化,使用

2.1二维数组的创建

     int arr[3][4]

2.2二维数组的初始化

int arr[3][4]={1,2,3,4};依次往进放入,不够的时候补0,不完全初始化
Int arr[][4]={{2,3},{4,5}}; 二维数组可以省略行的大小,但列不可以,会报错。
为什么不可以省略列呢?
比如:int arr[][4]={{1,2},{3,4}} 调试监视可以看到第一行1 2 0 0,第二行是3 4 0 0
如果是int arr1[][]={{1,2},{4,5}} 都不清楚一行有几个元素,第一行 1 2之后究竟有没有别的元素不清楚。
依次类推,n维数组的初始化,第n个[]不可以省略。

2.3二维数组的使用

在这里插入图片描述
同样利用下标进行使用
把二维数组理解成一维数组的数组(进一步加深对二维数组的理解)
比如访问第一行的元素arr[0][j],arr[0]当作一维数组的数组名
在这里插入图片描述

2.4二维数组在内存中的存储(也是连续存储的)

在这里插入图片描述

int main()
{
	int arr[3][4] = { 1,2,3,4,2,3,4,5,3,4,5,6 };
	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;
}

在这里插入图片描述
不难发现,二维数组的元素在内存中也是连续进行存储的。

三、数组越界

数组的下标是有范围限制的,数组的下标是从0开始,最后一个元素的下标是n-1;如果数组的下标小于0或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。C语言本身是不做数组下标的越界检查,编译器不报错,不代表程序是正确的。因此,自己最好做一下越界的检查。
比如:
在这里插入图片描述
a数组只有5个元素,却进行打印第10个元素,显然超出了数组的范围,便出现了一些奇怪的数值。
那么如何进行预防数组越界的情况呢?
借用sizeof函数来计算数组的长度,便不会出现索引数组长度之外的元素。
在这里插入图片描述

四、数组作为函数参数(以冒泡排序为例)

冒泡排序的核心思想
两个相邻的元素进行比较,一趟冒泡排序结束之后,一个数据会来到它最终应该出现的位置上!
在这里插入图片描述
对于冒泡排序,每一趟只能将一个数据排在它该排的位置,因此,对于n个元素的冒泡排序,便需要n-1趟来完成排序,并且在每一趟结束之后,需要两两相邻比较的对数也在减少。
经典错误!!!

void bubble_sort(int arr[])//要有[]
{
//趟数
	int sz = sizeof(arr) / sizeof(arr[0]);     //容易犯错的地方
	int i = 0;
	for (i = 0; i < sz - 1; i++)
	{
	//一趟冒泡排序
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)   //每结束一趟的比较,所需要的比较的相邻对数减1
		{
			if (arr[j] > arr[j + 1])
			{
				//利用中间变量进行交换
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}

		}
	}
}
int main()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	bubble_sort(arr); //数组传参,给数组名称即可
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (i = 0; i < sz; i++)
	{
		printf("%d\n", arr[i]);
	}
	return 0;
}

在这里插入图片描述
为什么结果会是这样呢?
在这里插入图片描述
通过调试,不难发现,sz的值为1,那么在子函数便没有进行循环的做法。
在这里插入图片描述
原因在于数组名本质上(除了两种特殊的情况)是数组首元素的地址。
因此sz的计算就会出现问题,为了解决这一问题,将sz的计算放在主函数中,并将sz作为参数传入到冒泡排序的函数中。
修改后的代码`
对于数组传参的时候,形参有两种形式:数组和指针的形式

//冒泡排序的函数,并且形参是指针的形式
void bubble_sort(int* arr, int sz)//趟数
//形参是数组的形式
//void bubble_sort(int arr[],int sz)//要有[],[]中大小,可写可不写
	int i = 0;
	for (i = 0; i < sz - 1; i++)
	{
	//一趟冒泡排序
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)   //每结束一趟的比较,所需要的比较的相邻对数减1
		{
			if (arr[j] > arr[j + 1])
			{
				//利用中间变量进行交换
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}

		}
	}
}
int main()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };

	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr,sz); //数组传参,给数组名称即可
	for (i = 0; i < sz; i++)
	{
		printf("%d\n", arr[i]);
	}
	return 0;
}

但在下面的两种情况下,数组名不表示数组的首元素的地址
1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节。
2.&数组名,这里的数组名表示整个数组,取的是整个数组的地址
在这里插入图片描述
这个说明数组名是作为数组的首元素的地址的
在这里插入图片描述
&arr是作为数组的地址,而不是首元素的地址的。数组+1地址,表示跳过整个数组
第5个和第6个差值为十六进制的0x28(换算为10进制就是2*16+8=40),即就是整个数组。
在这里插入图片描述
arr表示的是二维数组的第一行的地址(和第一行第一列的地址虽然一样)但是arr+1的地址,就是二维数组的第二行的地址,而不是第一行第二列的元素的地址。
计算二维数组的行数和列数

int main()
{
int arr[3][4] = { 0 };
//sizeof(arr)计算整个二维数组的大小,sizeof(arr[0])计算二维数组第一行的大小
printf("%d\n", sizeof(arr) / sizeof(arr[0]));
//sizeof(arr[0])计算二维数组第一行的大小,sizeof(arr[0][0])计算二维数组第一行第一列元素的大小
printf("%d\n", sizeof(arr[0]) / sizeof(arr[0][0]));
return 0;
}

在这里插入图片描述

总结

以上就是关于一维,二维数组的创建,初始化,使用,以及简单的冒泡排序的介绍。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值