这一章我们讲到了数组,包括一维数组、二维数组、数组越界、数组作为函数参数的知识。
首先我们来介绍一下一维数组:数组是一组相同类型元素的集合,数组创建的方式是:元素类型+数组名+[常量表达式],[]里面一定是常量,表示数组中有多少个元素,const(常变量)也不行,c99之后[]中可以用变量,但是不可以初始化。一维数组的初始化有四种方式:1、完全初始化,每一个对应的下标都有元素;2、不完全初始化,没有输入数值的元素(剩余元素)默认为0(推荐这个方式进行初始化int arr[10]={0};3、int arr[]={1,2,3,4,5,6};可以不指定元素个数,由编译器来数;4、int arr[10]={};里面元素随机,这是四种数组初始化的方式。一维数组的使用方式也比较简单,下标引用操作符,左边是数组名,操作符里面是数字(从0开始),整个数组的大小可以通过sizeof(arr)/sizeof(arr[0])来获得,这里的arr表示的是整个数组,是一种特殊情况,后面我们会仔细研究arr。一维数组在内存中的存储是连续的(一串相同类型的元素连续分布在内存里,随数组下标升高,地址也由低到高),int arr[10];中arr是首元素的地址&arr[0]==arr,arr+1得到arr[1]中的值,因此这样可以通过地址来访问数组了。
第二是二维数组,二维数组的创建和一维数组类似,int arr[2][5],从表面来理解,这是一个二行五列的数组,二维数组在内存中的存储方式也是连续的下标由低到高,地址由低到高,因此一个二维数组有种不同的理解方式,可以将其看作一个含有行数*列数个的一维数组,两者在内存中存储方式完全相同,二维数组中的每一行都可以相成一个一维数组,因此计算二维数组的行数:sizeof(arr)/sizeof(arr[0]),计算列数:sizeof(arr[0])/sizeof(arr[0][0]),不论是一维数组还是二维数组都存在越界的情况,二维数组使用起来要比一维数组要顺心应手一些,比如希望创建一个棋盘,一维数组可以创建,但是访问的时候不是学习过的人没有办法理解,或者写一些代码来进行转换比较麻烦。
下面就是数组作为函数的参数,往往我们在写代码的时候,要将数组作为参数传入函数内,要对数组内部进行修改,因此要传数组首元素的地址进去,也就是数组名,传入函数的是地址,我们在函数内部可以通过地址来找到数组,因此在函数内部就无法计算数组的长度了,要在主函数中就求出长度再通过参数传入函数中。我们这里为了解决看困惑,来详细聊一下arr(数组名)到底表示什么,除了两种特殊情况之下,数组名都代表首元素的地址,特殊情况有两种:1、sizeof(数组名),此时数组名代表整个数组,计算整个数组占用内存的大小,单位是字节;2、&数组名,这里数组名也表示整个数组的地址,虽然大小和首元素地址相同,但是arr+1(首元素地址+1)表示的是下一个下标的地址,而&arr+1代表的是数组的地址+1,地址会增大数组内元素个数*sizeof(类型)。arr[i]完全等价于*(arr+i),因此在函数中可以通过下标或者地址的方式来找到数组中的元素。
下一个是一种较为简单的排序算法:冒泡排序。数组内有一个组无序排列的数字,让它有序起来,冒泡排列的思想是:两两元素进行比较,有可能的话进行交换,首先确定有n个数字要参与排序,所以一共需要排n-1趟(前n-1个数字都放好了,最后一个数字也放好了),每一趟需要比较(n-1-这是第i趟)对数字,如果要升序排列,若比较前面的数字大于后面的数字就进行交换。
最后补充一点:数组和变量一样也是有类型的,例如:int arr[10];这个数组的类型就是将数组名去掉:int [10]就是数组的类型,sizeof(int [10])计算出来这个类型的数组占用空间的大小是40。