C语言数组详解

本文详细介绍了C语言中一维和二维数组的创建、初始化、使用、存储以及数组越界的概念,包括作为函数参数的应用,以冒泡排序为例。
摘要由CSDN通过智能技术生成

目录

一、一维数组

1.一维数组的创建

2.一维数组的初始化

3.一维数组的使用

4.一维数组的存储

二、二维数组

1.二维数组的创建

2.二维数组的初始化

3.二维数组的使用

4.二维数组的存储

三、数组越界

四、数组作为函数参数

冒泡排序

五、总结

一、一维数组

1.一维数组的创建

首先我们要了解数组是什么,数组是一组相同类型元素的集合,数组中会存放一组数。

数组的创建方式如下:

type_t   arr_name   [const_n];
//type_t 是指数组的元素类型
//const_n 是一个常量表达式,用来指定数组的大小
我们可以举几个例子来看一下:
int arr[10] = { 1,2,3,4,5,6,7,8,9,0};

这里可以看见,我们创建的类型是int,创建的数组名是arr,它包含了10个元素,为0,1,2,3,4,5,6,7,8,9.

那么,[]内我们刚刚放的是常量10,它里面可以放变量吗?根据规定,数组创建,在C99标准之前,[]中要给一个常量才可以,不能使用变量。在C99标准支持了变长数组的概念,数组的大小可以使用变量指定,但是数组不能初始化。

2.数组的初始化

数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值(初始化)。
初始化的值用大括号括起来,用逗号将值隔开。
我们在这里引入一个操作符:[] ,下标引用操作符。它其实就是数组访问的操作符。
我们可以看以下代码进行理解:
I. int arr1[10] = {1,2,3};//这里有10个元素,全只在大括号内放入3个—1,2,3  ,这里便是不完全初始                                        //化,剩余7个元素默认都是0.
II. int arr2[] = {1,2,3,4}; //这里[]内没有填写常量,省略了数组的大小,但是数组可以初始化,数组                                       //的大小根据初始化内容来确定。 
III. int arr3[5] = {1,2,3,4,5};//这里数组的大小和初始化内容完全对应,就是完全初始化。
 
数组在创建的时候如果想不指定数组的确定的大小就得初始化。数组的元素个数根据初始化的内容来确定。
3.一维数组的使用
首先我们要理解两点:
1. 数组是使用下标来访问的,下标是从 0 开始。
2. 数组的大小可以通过计算得到。
根据第一点,如果我们创建一个数组:int arr[3] = {1,2,3};   那么数组的下标分别对应的是:1—下标0、2—下标1、3—下标2。如果我们想在屏幕上打印数字2,我们就要输入printf(“%d”,arr[1]);
我们可以看一下代码:

根据第二点,我们知道数组的大小可以通过计算得到,我们创建一个数组:int arr[] = {1,2,3};

我们可以使用sizeof来进行计算,sizeof(arr)是整个数组的大小,sizeof(arr[0])是数组中一个元素的大小,我们用sizeof(arr)/sizeof(arr[0])就可以求出数组的大小啦,我们看一下代码:

 

 通过以上两点,我们可以尝试写一个代码,利用数组在屏幕上打印0—9:

4.一维数组的存储

接下来我们探讨数组在内存中的存储。

首先我们定义一个数组 int arr[3] = {1,2,3};  我们在来看看三个元素分别对应的地址:

 我们把结果拿出来看:&arr[0]=0000000EAE2FF8B8
                                     &arr[1]=0000000EAE2FF8BC
                                     &arr[2]=0000000EAE2FF8C0

我们发现每个地址之间相差4个字节,随着数组下标的增长,元素的地址,也在有规律的递增。

由此可以得出结论:一维 数组在内存中是连续存放的。

二、二维数组

1.二维数组的创建

二维数组创建的方式和一维数组一样,不同的是它的下标引用操作符有两个,第一个代表行,第二个代表列。例:我们想创建一个三行四列的整型数组  int arr[3][4];

2.二维数组的初始化

二维数组初始化,每行内容用大括号括起来,大括号内每个元素用逗号隔开,每列之间也用逗号隔开,最外面有一个大括号将所有元素括起来。

I. int arr[3][4] = {1,2,3,4}; //初始化了第一行的内容,第二行和第三行默认都是0.

II. int arr[3][4] = {{1,2},{4,5}};//初始化了第一行的第一,第二列元素,分别为1和2。                                                                      // 初始化了第二行的第一,第二列元素,分别为4和5。其余都默认是0.

III. int arr[][4] = {{2,3},{4,5}};//二维数组如果有初始化,行可以省略,但是列不行

IIII. int arr[2][2] = {1,2,3,4};  //如果没有使用大括号分隔每行元素,则按顺序补充,补满第一行就自                                              //动换行补充。

3.二维数组的使用

    二维数组的使用基本和一维数组一样,不管是行还是列,二维数组下标也都是从0开始的,如我们初始化一个三行两列的二维数组:  int arr[3][4] = {{1,2},{3,4},{5,6}};  我们想在屏幕上打印5,那么打印的行下标为2,列下标为0, 就是arr[2][0],我们可以看一下代码:

 我们也可以通过二维数组在屏幕上打印0-5:

4.二维数组的存储

我们可以想一维数组一样,打印它每个元素地址进行查看:

这是其运行结果:

&arr[0][0]=00000040F892F898
&arr[0][1]=00000040F892F89C
&arr[0][2]=00000040F892F8A0
&arr[1][0]=00000040F892F8A4
&arr[1][1]=00000040F892F8A8
&arr[1][2]=00000040F892F8AC 

我们发现每个地址之前还是相差4个字节,由此我们可以发现,二维数组在内存中也是连续存储的。

三、数组越界

1.数组的下标是有范围限制的。
2.数组的下规定是从0 开始的,如果数组有 n 个元素,最后一个元素的下标就是 n-1 。 所以数组的下标如果小于0 ,或者大于 n-1 ,就是数组越界访问了,超出了数组合法空间的访问。
3.C 语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的,所以程序员要自己做好越界的检查。

我们可以利用一个代码进行讲解:

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

我们发现其实这个代码是错误的,在用for循环时候,其的条件判断部分是i<=10,这会导致程序访问了数组中下标从0—10的元素,有11个元素,但是数组arr中只有10个元素,这就会造成数组越界,但是程序是能跑起来的,我们来看运行结果:

 我们可以发现运行结果是错误的,最后出现了一个错误的数字,但是程序并没有报错,可以正常运行,所以这种越界的错误就需要我们程序员自己进行检查。我们也要注意:二维数组的行和列也可能存在越界。

四、数组作为函数参数

往往我们在写代码的时候,会将数组作为参数传给函数。数组传参,传递的是首元素地址

下面我们来写一个降序的冒泡排序的函数:

首先我们要知道什么是冒排序:通关两两相邻的元素进行比较和交换,从而实现数组中的数按一定顺序进行排序,而一趟冒泡排序可以让一个值来到最终应该出现的位置上。

所以我们要明确我们的目标

1.确定冒泡排序的趟数

2.一趟冒泡排序的实现

对于1,我们可以先求出数组包含的元素个数,随后从第一个数和第二个数开始进行比较和交换,最终交换完毕。

对于2,我们需要进行一定判断,代码如下:

if (arr[j] < arr[j + 1])
{
	int tmp = arr[j];
	arr[j] = arr[j + 1];
	arr[j + 1] = tmp;
}

现在我们来写一下这个代码:

 

void bubble(int arr[10], int sz)
{
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		int flag = 1;
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (arr[j] < arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				flag = 0;
			}
		}
		if (flag == 1)
		{
			break;
		}
	}
}
int main()
{
	int i = 0;
	int arr[10] = { 4,1,5,6,8,3,7,9,2,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble(arr, sz);
	for (i = 0; i < 10; i++)
	{
		printf("%d", arr[i]);
	}
	return 0;
}

这样子,我们就可以顺利的实现冒泡排序了,要注意:

除此1,2两种情况之外,所有的数组名都表示数组首元素的地址

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

2. &数组名,取出的是数组的地址。&数组名,数组名表示整个数组。
五、总结
我们学习完数组的内容啦,到现在我们就可以自己进行一些操作来检验我们的学习成果,我们可以做一个三子棋或者扫雷的小游戏,希望大家能越学越好!
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值