什么是数组
数组(Array)是一种用来存储同一种类型的集合,是一种有序的线性结构表。并且数组元素的地址是连续的。
数组最大的优点就是支持随机访问,当想访问数组的某个数时,只需要找到数组的对应下标就可以直接找到该数组对应元素。但是数组也有相应的缺点,那就是数组的元素个数和数组空间大小在创建时就已经被固定死了,如果数组的空间没有使用完也会造成空间浪费,并且因为数组的地址是连续的,这本应该是一个优点的,但是这导致数组在进行删除或增加元素时需要O(n)才能完成。
数组的下标
数组下标是从0开始的,假设,访问arr[5]元素时,访问的是数组的第6个元素,访问arr[0]时,访问的是数组的第一个元素。
一维数组
一维数组创建
一维数组是常见的数组,创建方法是:数据类型 + 数组名 [ 元素个数 ];
1 | int arr[10]; |
在C99的标准之前,当数组在创建时,方括号内的数组元素个数只能是常量,使用的常量也必须是真正意义上的常量,比如用const修饰的变量有了常属性,但不是真正意义的常量,而由define定义的常量可以用来做数组元素个数。而C99之后数字方括号内的元素可以使用变量,而使用变量的做数组元素个数的数组,叫做变长数组。
一维数组初始化
1 2 3 4 | int arr[10] = {1,2,3,4,5,6,7,8,9,10}; //整形数组 int arr[] = {0} //不指定大小但必须初始化 char ch[10] = { '1' , '2' , '3' }; //字符数组 char str[10] = "abcde" ; //字符串数组 |
一维数组的赋值
用循环变量访问数组下标,给数组进行赋值。%s对应的是输入一个字符串,需要提供一个字符数组来存储,数组名是一个地址,所以不用加&取地址。
1 2 3 4 5 6 7 8 | int arr[10] = {0}; for ( int i = 0;i < 10;i++) { scanf ( "%d" ,&arr[i]; } char str[10] = {0}; scanf ( "%s" ,str); //字符串赋值可以不取地址和循环 |
一维数组在内存的存储方式
一维数组的元素地址是连续的,也就是元素的地址一个紧挨着一个。地址在内存是以二进制进行存储的,但是如果以二进制来展示的话就会非常的长而且也未必好理解,所以就由十六进制来进行展示。(下图)观察下图可发现,地址的是由低到高随着下标增长而增长的,有规律的递增,且每个数组元素地址都相差了四个字节,相差的四个字节是一个int整形的空间大小。
二维数组
二维数组在我们的逻辑概念中可以是一个矩阵,但在内存中与一维数组一样是一个连续的地址空间。通常我们将二维数组的第一个方括号看做行,第二个方括号看做是列。
二维数组的创建和初始化
二维数组与一维数组只是多加了一个方括号。数据类型 + 数组名[元素个数][元素个数];
1 2 3 4 5 | int arr[3][3] = {1,2,3,4}; //4自动存到arr[1][0]的位置 int arr[3][3] = {{1,2,3}, {4,5,6}, {7,8,9}}; //一个大括号代表一行,每个大括号以逗号隔开 int arr[][3] = {0}; //二维数组可以不初始化行,但必须初始化列 |
二维数组的赋值
给二维数组赋值,与一维数组一样都需要循环来搞定,但是二维数组需要在一维数组的循环基础上再嵌套一层循环。
1 2 3 4 5 6 7 8 | int arr[3][3] = {0}; for ( int i = 0;i < 3;i++) { for ( int j = 0;j < 3;j++) { scanf ( "%d" ,&arr[i][j]); //i访问行,j访问列 } } |
数组越界
数组的下标范围是有限的,因为数组的下标是由0开始的,所以数组能访问的的下标就是数组元素个数减一个(N-1),当访问了不属于数组元素地址范围的空间,就叫做数组越界。假设一个arr[10]的数组,当访问下标时大于等于10的时候,就会导致数组向后溢出,也叫下溢出,相对的,当数组向数组第一个元素的前面越界访问时,也就是下标小于0,就叫上溢出,越界访问是非常危险的一个操作,因为有的编译器没有检查数组是否越界的功能,所以,当程序员在写代码所以数组时,要非常注意数组是否存在越界问题。二维数组的行和列也同样
数组名
数组名是指向数组首元素地址的指针,即下标为0的元素的地址的指针。上面说,由于数组的地址是连续的,所以当找到数组的首元素就可以找到数组的其他成员。如果用sizeof(数组名),这里的数组名代表的是整个数组,计算的是整个数组的大小。再除以sizeof(下标为0的地址),就可以得到数组的元素个数。
数组的传参方式
当要将数组作为函数参数进行传参时,需要在函数的传参位置放一个数组名,形参部分就会接收到一个数组的首元素地址的指针,而接收这个指针就也需要同类型的指针。在形参部分,数组可以有两种形式表示,一种是以数组的形式,一种是以指针的形式,两种方式都可以对数组进行传参。
12void
bubble_sort(
int
arr[])
void
bubble_sort(
int
* arr)
当数组在传参之后,函数部分是不能计算数组的元素个数的。因为形参接收的只是一个数组的首元素地址的指针,而不是整个数组,计算数组的时候也只是计算了数组的首元素地址的大小,然后再除以首元素地址的大小,所以理所当然的得到一个1。所以,当数组需要传参,并且还需要用到数组的元素个数时,要先计算好数组元素个数,将计算好的元素个数和数组一起传参。
结尾
数组其实不只有一维和二维数组,还有三维数组甚至更高维,但是在情况下很少会用到,而且对于初学者用到二维数组就已经足以。