一、一维数组
1.1 一维数组的声明1.2 一维数组的初始化1.3 引用数组元素1.4 一维数组在内存中存储 二、二维数组
2.1 二维数组声明2.2 二维数组的初始化2.3 引用数组元素2.4 二维数组在内存中存储 三、多维数组
3.1 多维数组声明3.2 多维数组初始化 四、数组下标越界
4.1 下标越界访问4.2 下标越界修改 五、数组与指针
5.1 数组名
5.1.1数组名是什么5.1.2 数组名两个例外 5.2 下标引用与指针表达式5.3 数组与指针区别 六、数组与函数
6.1 一维数组传参的函数设计6.2 二维数组传参的函数设计
数组:一组相同类型元素的集合 一、一维数组 1.1 一维数组的声明
元素类型 数组名[元素个数]
说明:元素个数一般为常量表达式,c99标准支持可变长数组,即元素个数可以使用变量表示
int arr[10]; //声明一个整形数组,数组有10个元素,数组名为arr
1.2 一维数组的初始化初始化:在数组声明时为数组赋值
int arr1[5] = {1,2,3};int arr2[5] = {1,2,3,4,5};int arr3[] = {1,2,3};char arr4[] = "abc" //等同于 arr4[] = {'a','b','c',''};
说明:
1.在数组声明时为数组赋值,可省略数组元素个数,此时元素个数为初始值个数
int arr3[] = {1,2,3}; //元素个数为:3
2.如果初始值个数小于元素个数时,剩余数组元素值被初始化为0
int arr1[5] = {1,2,3}; // 等同于 int arr1[5] = {1,2,3,0,0};
3.只能在数组声明时为数组赋值,其他时候只能为数组元素赋值,不能为数组赋值
int arr1[5];arr = {1,2,3,4,5}; //错误int arr2[] = {1,2,3};int arr3[3];arr3 = arr2;//错误
1.3 引用数组元素 数组名[下标]
说明:
1.数组元素通过下标来访问
2.数组下标从0开始,下标范围为[0,size-1]
3.size = sizeof(arr) / sizeof(arr[0]); 函数内此公式不适用
#include
输出
1 2 3 4 5
1.4 一维数组在内存中存储一维数组在内存中是连续存放的,地址使用是从低地址到高地址
#include
输出
010FFD80010FFD84010FFD88010FFD8C010FFD90
二、二维数组 2.1 二维数组声明 元素类型 数组名[行数][列数]
数组元素个数=行数*列数,在声明时行数可以省略(但必须初始化)
int arr[3][2]; //声明一个二维数组,数组名为arr,数组有3行2列,元素个数为3*2,元素类型为int
2.2 二维数组的初始化初始化:在数组声明的时候为其赋值
int arr1[3][3] = {1,2,3};int arr2[2][2] = { {1},{2,3} };int arr3[][2] = { {1,2},{3,4} };
说明:
1.初始值个数少于行数与列数乘积,剩余数组元素被初始化为0
int arr1[3][3] = {1,2,3}; // 等同于 int arr1[3][3] = { {1,2,3},{0,0,0},{0,0,0} };//或等同于 int arr1[3][3] = {1,2,3,0,0,0,0,0,0};
2 只能在数组声明时为数组赋值,其他时候只能为数组元素赋值
int arr1[2][3] = { {1,2,3},{4,5,6} };int arr2[2][3];arr2 = arr1;//错误arr2[0] = arr1[0] //错误arr2[0][0] = arr1[1][1];//正确
2.3 引用数组元素 数组名[行下标][列下标]
行下标:范围为 [0,行号-1]
列下标:范围为 [0,列号-1]
#include
二维数组在内存中是连续存放的,地址使用是从低地址到高地址
#include
输出
&arr[0][0] = 00B8FE6C&arr[0][1] = 00B8FE70&arr[0][2] = 00B8FE74&arr[1][0] = 00B8FE78&arr[1][1] = 00B8FE7C&arr[1][2] = 00B8FE80
三、多维数组多维数组:维数大于1个称为多维数组,如:二维数组、三维数组、四位数组等
3.1 多维数组声明int arr[3][4][5];//声明1个三维数组,数组名为arr,数组为3排、4行、5列,元素个数=3*4*5,元素类型为int
3.2 多维数组初始化int arr1[2][2][2 = { { {1,2},{3,4} },{ {5,6},{7,8} } };
说明:多维数组中,只有第一维才能根据初始化列表缺省的提供,剩余的几维必修显式地写出
int arr1[][2][2 = { { {1,2},{3,4} },{ {5,6},{7,8} } }; //第一维度省略不写,通过计算子数组的个数,得到第一维度为2
四、数组下标越界数组的下标是有范围的,下标范围为[0,元素个数-1],当下标不在此范围时就超出数组合法空间的访问,即数组下标越界。C语言标准并不规定数组下标越界检查,下标越界检查涉及开销比想象的多(涉及到指针指向空间是否在数组空间内),所以大部分编译器不做下标越界检查
4.1 下标越界访问#include
输出
arr[-1] = -858993460arr[5] = -858993460
大部分编译器对越界访问只会报警告,程序仍旧可以运行
4.2 下标越界修改#include
程序错误,Run-Time Check Failure #2 - Stack around the variable ‘arr’ was corrupted.
结论:我们要自己对数组下标是否越界做检查,不要指望编译器
五、数组与指针 5.1 数组名 5.1.1数组名是什么在C中,几乎所有使用数组名的表达式,数组名是数组首元素地址,是一个指针常量
例1
#include
输出
p = 008FFE64&arr[0] = 008FFE64
例2
#include
只有在两种情况下,数组名不是数组首元素地址
例外1:sizeof(数组名)
#include
输出
20
例外2:&数组名
#include
输出
&arr = 004FF924&arr[0] = 004FF924arr = 004FF924---------------&arr+1 = 004FF938&arr[0]+1 = 004FF928arr+1 = 004FF928
5.2 下标引用与指针表达式我们之前访问(修改)数组元素时是使用下标引用,但我们知道数组名一般情况下就是数组首元素的地址,是一个指针常量,所以本质上下标引用是指针表达式的伪装。
*array[subscript ] 等同于 (array + subscript )
#include
输出
使用下标引用方式打印元素值1 2 3 4 5使用指针表达式方式打印元素值1 2 3 4 5
当指针在表达式左边时,修改指针指向空间存放的值
当指针在表达式右边时,访问指针指向空间存放的值
#include
输出
*p = 10i = 10arr[0] = 10
说明:
1.下标引用相对于指针表达式可读性更强
2.下标引用绝不会比指针更有效率,但指针有时会比下标引用更有效率
数组和指针并不是相等的
声明一个数组时,编译器根据声明所指定的元素个数为数组分配内存空间,然后再创建数组名,它的值是一个常量,指向这片空间的起始位置。声明一个指针变量时,编译器只为指针本身分配内存空间,如果指针变量是一个全局变量则默认初始化为NULL,如果是局部变量不会被初始化,存放的是一个随机地址值 六、数组与函数 6.1 一维数组传参的函数设计 一位数组数组名是数组首元素地址
当在一个函数内部使用外部某个一维数组时,需要将该一维数组传入函数内,我们之前一般设计为数组形式
例1:
#include
例2 :
我们发现例1设计时,函数写死了,数组元素个数只能为5,当外部数组元素个数不是5的时候,函数需要修改,有些人会想到在函数内部通过 sizeof(arr) / sizeof(arr[0])求元素个数,这是一种错误设计方法
#include
例3:
通过例2我们知道,如果在函数内部需要知道外部数组元素个数,可通过一个显式的参数传递给函数,指明数组元素个数
#include
例4
我们知道一维数组的数组名为数组首元素地址,所以函数参数设计时应该用指针类型
#include
结论:
1.一维数组传参传递的是数组首元素地址,本质是指针
2.我们推荐使用例3、例4的方式进行函数设计,尤其是例4
二维数组的数组名是首元素地址,首元素是一个一维数组,即数组指针
int arr[3][4];int (*p)[4] = arr; //p存放数组arr首元素地址 // 下标引用运算符优先级高于间接访问运算符,但是由于小括号存在,p首先与*匹配,即p是指针。接下来与// 下标引用运算符匹配,表明p指向某种类型的数组,最后与int匹配,所以p是一个指向数组的指针,数组有10个// 元素,每个元素为int类型
当在一个函数内部使用外部某个二维数组时,需要将该二维数组传入函数内,我们之前一般设计为数组形式
例1:
#include
例2:
我们发现例1设计时,函数写死了,数组的行和列只能为2,其他情况函数需要修改。可通过2个显式的参数传递给函数,指明行和列
#include
例3
我们知道二维数组的数组名为数组首元素地址,即1个一维数组的地址,所以函数参数设计时应该用指针类型
#include