数组的初步认识

数组的概念

数组是一组相同类型元素的集合,这些元素的类型必须是相同的,可同时存放一个或多个数据。

其中,数组包括一维数组和多维数组,一维数组和二维数组是我们今天要重点介绍的。

一维数组的创建和初始化

数组的创建

数组的语法形式为

type arr_name [常量值];

存放在数组的值被称为数组元素,数组在定义时也可以定义大小和类型

在这条语法形式里,type指的是内置类型,arr_name则是自定义的数组名,[]内的常量值代表着数组大小

我们在使用数组之前,需要将数组进行初始化,即将介绍的就是,数组初始化的方法

数组的初始化

数组的初始化可以分为三种,我们只介绍完全初始化和不完全初始化

完全初始化

完全初始化可以简单理解为,定义的所有元素个数与定义的数组大小相同

如以下定义

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

在这个数组中,我们定义了一个数组大小为5,而我们把所有的5个元素都定义了一个具体值,这就是完全初始化

不完全初始化

与完全初始化不同的是,不完全初始化则是元素个数与定义的数组大小不同,如

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

显然,大括号内的元素个数并不满足定义的数组大小10个,难道说剩下的空间就什么都不放吗?

其实不是,剩余的元素会自动初始化为0。

当然,我们还要掌握一种情况,如果数组初始化了,是可以省略数组大小的,就像以下定义

int num[]={1,2,3};

在num这个数组中,我们初始化了三个元素分别为1,2,3

数组的类型

数组是有类型的,是一种自定义类型,如果去掉自定义的数组名,剩下来的部分就称作数组的类型。如

int arr[50];
char ch[10];

上面数组的类型是int [50];,下面数组的类型则是char [10];

即都为去掉数组名后剩下来的部分

一维数组的使用

一维数组是可以用来储存数据的,那具体改怎么使用,是我们接下来要介绍的

数组下标

在数组中,每个元素都对应着一个数组下标。

假如数组有十个元素

int arr[10]={1,2,3,4,5,6,7,8,9,10};

分别对应的下标如下

元素 1 2 3 4 5 6 7 8 9 10
下标 0 1 2 3 4 5 6 7 8 9

显然,数组下标是从0开始记录的。那么,有n个元素,最后一个数的下标就是n-1。

我们需要记住的是:数组元素通过打印下标的方式来进行打印

具体该如何操作,假设我们要打印数组中的元素5

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%d", arr[4]);
	return 0;
}

程序运行的结果则是数组的初步认识_第1张图片

 很显然,打印数字5时我们用到的则是5的下标4。

为了找到下标,我们使用了C语言中的下标引用操作符,即[ ],在这段代码中,printf函数里的arr[4]

即引用下标为4的元素5,这样我们就能理解数组下标的作用,是帮助我们找到数组元素的了。

如果我们想要打印数组里面的所有元素,将是这样的

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 ", arr[i]);
	}
	return 0;
}

输出的结果是

数组的初步认识_第2张图片

 使用一个for循环,再用下标操作引用符引用0~9下标便能打印出数组1~10的数。

数组的输入

还是1~10的数组,我想要实现输入一个数组下标,找到对应的数组元素,要实现以下代码和结果

数组的初步认识_第3张图片

 如果我们想要给数组输入自己想要的数据,可以用以下代码实现

int main()
{
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	int i = 0;
	for (i = 0;i < 10;i++)
	{
		scanf("%d", &arr[i]);
	}
	for (i = 0;i <10;i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

我们需要记住的是,    int arr[10] = {1,2,3,4,5,6,7,8,9,10};这段代码只是将数组里的元素初始化了,什么叫初始化?如果后面的代码没有改变元素,输出的就是初始化的元素。但是在这段代码里,我们引用了scanf函数以此来输入我们想要的数组元素,来进行打印。

我们随机输入十个数字,得到的结果是这样的

数组的初步认识_第4张图片

 一维数组在内存中的存储

为了能够表达数组的元素个数,我们需要先了解一维数组在内存中的储存,通过下面一条代码来看

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("&arr[%d]=%p\n", i, &arr[i]);
	}
	return 0;
}

程序运行的结果则是

 数组的初步认识_第5张图片

 看得出来,每个连续的元素之间相差了四个字节(因为一个整型是4个字节),所以,我们能够得到数组在内存中是连续存放的这样一个结论。

数组的元素个数

在定义数组时,我们常常会定义数组大小,可以直接知晓数组里面的元素个数。

但是如果我们并没有定义数组大小,却想要应用数组的元素个数,就需要用到sizeof来计算数组元素个数了。

sizeof是C语言中的一个关键字,可以计算类型或变量大小的,我们先看看sizeof的使用

int main()
{
	int arr[10] = { 0 };
	printf("%d\n", sizeof(arr));
	return 0;
}

看这组代码,我们定义了一组数组含有十个元素0,每个元素所占的内存是4个字节,所以,输出的数应该是40,那我们看看运行的结果是数组的初步认识_第6张图片

 结果在我们的预测之中,正是40.

40所代表的是数组内所有元素总共占的内存,如果我们想要知道数组的元素个数,则还需知道单个元素所占有的内存,我们只用选择数组的第一个元素即可,即arr[0] 。

接下来,我们就能计算出一个数组的元素个数了,需要用到的代码如下

int main()
{
	int arr[10] = { 0 };
	printf("%d\n", sizeof(arr)/sizeof(arr[0]));
	return 0;
}

用数组占的总内存除去数组单个元素占的内存就是数组个数,在这条代码中的数组个数应该为10,那么我们运行一下看看结果是不是10

数组的初步认识_第7张图片

 很容易就能得到,结果是10,这就是计算数组元素个数的方法,能够灵活应变。

一维数组的概念,大致就这么多,接下来要介绍的是二维数组

二维数组

二维数组简单点概括就是把一维数组作为数组元素,从它的语法形式就能看出来

typr arr_name[常量值1][常量值2]

二维数组的创建

二维数组的创建其实和以为一维数组大差不差,就是两个常量值代表着不同的意义。

常量值1代表着行数,常量值2代表着列数,可以这么定义

int arr[3][5];
chae ch[4][6];

第一行代码:3代表有数组有3行,5则是数组有5列,int是内置类型,arr是数组名

二维数组的初始化

二维数组的初始化就有很多讲究的地方,先介绍完全初始化,假设是定义以下一个数组

int arr[3][5];

从之前的讲解我们很清楚这数组的组成是3行5列,如果我们要将第一行填满1,2,3,4,5。第二行填满2,3,4,5,6。第三行则填3,4,5,6,7。那么数组应该初始化为

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

只需要按顺序填好元素,便能完成二维数组的完全初始化

1 2 3 4 5
2 3 4 5 6
3 4 5 6 7

另外还有一种初始化的方式,按照行进行初始化。

为什么要按照行初始化呢?

想一下,以上面的二维数组为例,如果我要在第一行只输入{1,2},第二行输入{3,4},第三行只输入{5,6}。这时,我们就要按照行来初始化了。

得用以下代码实现

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

如果按照这样初始化,那么得到的二维数组将是

1 2 0 0 0
3 4 0 0 0
5 6 0 0 0

这样,我们就能满足行的元素的初始化

还有一种初始化,是省略行但不省略列的情况,可以有以下几种定义方式

int arr1[][5]={1,2,3};
int arr2[][5]={1,2,3,4,5,6,7};
int arr3[][5]={{1,2},{3,4},{5,6}};

分别用表格形式来呈现不同的二维数组

首先是arr1

1 2 3 0 0
0 0 0 0 0
0 0 0 0 0

其中行数不一定只用3行,但是一定是有5列的,1,2,3三个数先按顺序排到数组的第一行,排够了以后接下来的元素都初始化为0

arr2的表现形式则是

1 2 3 4 5
6 7 0 0 0
0 0 0 0 0

排列时依旧是按照顺序1~7这么排的,但是由于数组的初始化只有5列,那么第一行放满五个数以后自动放在第二行,而行数没有定义也是无限的。

arr3的形式是

1 2 0 0 0
3 4 0 0 0
5 6 0 0 0

这是在不限定行数情况下分行的初始化,未进行初始化的元素默认为零。

那么,我们可以思考一个问题,为什么可以省略行,而不可以省略列呢?

假设在初始化的时候行数不能省略,列数可以省略,这时,我们可以输入10个元素、20个元素甚至是上亿个元素。由于这时候数组没有列数的限定,初始化再多的元素,会填满这一行吗?会不会自动填到下一行中去呢?答案肯定是不会的,如果省略列数的话,二维数组就像是一维数组一样,虽然有可能有其他行的存在,但是其他行里的元素都为0,这样,二维数组的初始化就没有意义了,因此行能省略,列不能省略。

二维数组的下标

二维数组中,行和列的下标是分开来的,但是行和列的下标都是从0开始的,如下表

数组下标 0 1 2 3 4
0 1 2 3 4 5
1 2 3 4 5 6
2 3 4 5 6 7

通过这张表格,我们就能像坐标一样,快速定位每个数的位置。

假设我们要找第二行的数字3,可以用以下代码实现

int main()
{
	int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
	printf("%d", arr[1][1]);
	return 0;
}

在这条代码中,中括号内的1分别代表了行和列的下标,正是我们要找的3

所以,打印出来的结果如下

数组的初步认识_第8张图片

 很显然,条件满足

二维数组的输入与输出

我们还是以上面那个数组为例,通过循环的方法来实现二维数组的输入和输出。

int main()
{
	int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
	int i = 0;
	for (i = 0;i < 3;i++)//行数
	{
		int j = 0;
		for (j = 0;j < 5;j++)//列数
		{
			scanf("%d", &arr[i][j]);
		}
	}
	for (i = 0;i < 3;i++)
	{
		int j = 0;
		for (j = 0;j < 5;j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

我们随机输入15个数,得到的结果是

数组的初步认识_第9张图片

 这样,我们就能满足数组的输入

二维数组在内存中的存储

我们先通过一段代码来打印二维数组的内存

int main()
{
	int arr[3][5] = { 0 };
	int i, j = 0;
	for (i = 0;i < 3;i++)
	{
		for (j = 0;j < 5;j++)
		{
			printf("&arr[%d][%d]=%p\n", i, j, &arr[i][j]);
		}
		
	}
	return 0;
}

程序输出的结果则是

数组的初步认识_第10张图片

 从中我们可以读到,在一行里面,连续的元素之间相差了4个字节。但是在行与行之间,如arr[0][4]与arr[1][0],他们的内存空间也是相差了4个字节,可见,二维数组在内存中也是连续存放的,如下图所示

下标 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4
元素 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

这是将二维数组的每行元素头尾连续摆放的结果,显然元素连续存放的结论是成立的

由于VS中变长数组不能使用,暂不介绍。我们只需要记住一点不要用变量来指定数组大小,VS不支持。

数组的内容,大致就这么多了

The end

你可能感兴趣的:(算法,开发语言,c语言)