1、数组基础
1.1、数组的概念
数组是多个相同类型元素组成的一个集合 。
(一次性定义多个相同类型的变量,并存储到一片连续的内存中)
(1)数组的类型:数组元素的类型
(2)数组的元素:每个位置存放的内存
(3)数组的长度:数组元素的个数
(4)数组占用的空间大小:实际占用内存的内存大小,在数组定义的时候就确定好了。
(5)数组的下标:访问数组元素的时候,根据数组的下标来访问,第几个元素(从0开始,到数组的长度-1)
1.2、数组的定义和初始化
int a[5];//定义一个长度为5的整型数组,数组名字为a
语法:
1.a是数组名,即这块连续内存空间的名称
2.[5]数组的长度,代表这块连续的内存空间总共分为5个相同的格子,每个格子称为数组的元素
3.int代表每个元素的类型,可以是任意基本数据类型,也可以是组合类型,甚至可以是数组
初始化:
//正常初始化 int a[5] = {1,2,3,4,5};
//定义之后,按照数组下标挨个初始化
int a1[5];
a1[0] = 1; a1[1] = 2; a1[2] = 3; a1[3] = 4; a1[4] = 5;
//定义之后,通过循环输入进行初始化
int a2[5]; for (int i = 0; i < 5; ++i)
{
scanf("%d", &a2[i]);
}
int a3[5] = {1,2,3}; //可以,只初始化前3个,后面默认初始化
int a4[] = {1,2,3,4,5,6}; //可以,根据初始化列表来确定个数 //
int a5[5] = {1,2,3,4,5,6,7}; //不可以,越界 int a6[];
定义数组的时候,可以用变量来作为数组的长度进行定义
例:int n = 4;
int a[n];
但是,不能在定义的时候做初始化,不知道数组的长度怎么来确定
1.3、数组元素的访问和赋值
(1)数组在初始化的时候,可以一次性给多个元素赋值
(2)通过下标来,[x]
在定义的时候,[x],x是数组的总元素个数,int a[5];
在访问的时候,[x]表示的是数组元素下标(从0开始,到数组的长度-1),a[5]
n = a[5]; //拿到数组a下标为5的元素
a[5] = 10; //将数组a下标为5的元素赋值10
2、数组名的含义
(数组元素访问的内存逻辑)
数组名代表数组首元素地址(在绝大多数情况下都能适用)
但是sizeof(数组名),得到的是整个数组所占用的内存空间大小
数组可以通过下标来访问元素,怎么通过下标来找到元素呢???
arr[n] === *(arr+n)
nt a[5] = {1,2,3,4,5};
printf("%d\n", a[2]); //在内存的内部,以*(a+2)存在的
printf("%d\n", *(a+2));
scanf("%d", &a[2]); // a[2] 在内存的内部,
//以 *(a+2) 存在的
scanf("%d", (a+2));
//arr:数组首元素地址
//&arr:整个数组的地址
3、一维数组
3.1、一维数组定义和初始化
定义一个数组的时候,想要全部元素都初始化为0
int a[5] = {0};
而不是:
int a[5];//这样定义的数组是没有进行初始化的,不能确定数组的元素值是多少
3.2、一维数组的传参
数组传参本质上传入的是首元素地址,在函数里面,我们是通过首元素地址来访问到数组的所有元素的值,在函数里面做变更,在函数外面也会跟着变更
下面两个函数的效果是一样的
void func1(int *a)//以指针的形式 { for (int i = 0; i < 5; ++i) { printf("%d\t", a[i]); } printf("\n"); } void func2(int a[])//以数组的形式 { for (int i = 0; i < 5; ++i) { printf("%d\t", a[i]); } printf("\n"); }
注意:数组作为实参传递给函数的时候,拿到的是数组的首地址,在函数里面是得不到数组的长度,所以,我们在传数组的时候,通常,都是以参数的方式,把数组的长度传递过去
4、二维数组
概念:数组元素由多个相同类型的一维数组组成,若数组的类型也是数组,这种数组称为多维数组,二维数组也叫多维数组
4.1、二维数组定义和初始化
整型数组:每一个元素都是整数的数组
char型数组:每一个元素都是字符的数组
二维数组:每一个元素都是一维数组的数组
多维数组:每一个元素都是数组的数组
int a[2][3]; 释义: arr[2]:表示该数组有两个元素 int [3]:一个有三个元素的一维数组,每个元素的类型都是int
多维数组的语法跟一维数组语法完全一致
初始化:
//多维数组,数组的元素是另一个数组 i
nt a1[2][3] = {{1,2,3}, {4,5,6}}; //正常初始化 //
int a2[2][3] = {{1,2,3}, {4,5,6}, {7,8,9}}; //错误,越界了 //
int a3[2][3] = {{1,2,3}, {4,5,6,7}}; //错误,越界了
int a4[][3] = {{1,2,3}, {4,5,6}, {7,8}}; //可以,通过元素个数来确定数组的长度 //
int a5[3][] = {{1,2,3,4}, {4,5,6}, {7,8}}; //错误,不知道一维数组的长度
int a6[2][3] = {1,2,3,4,5,6}; //顺序依次初始化
int a7[2][3] = {0}; //初始化第一个,后面默认初始化
int a8[2][3] = {{1}, {4,5}};
int a9[2][3];
for (int i = 0; i < 2; ++i) //控制二维的元素个数
{
for (int j = 0; j < 3; ++j)
//控制一维的元素个数
{
scanf("%d", &a9[i][j]);
}
}
4.2、多维数组元素访问
:数组名相当于是首元素的地址
int a[2][3] = {{1,2,3}, {4,5,6}}; printf("%d", a[0][0]);//打印数组第一个元素里面的一维数组的第一个元素 printf("%d", *(*(a+0)+0));//打印数组第一个元素里面的一维数组的第一个元素 scanf("%d", &a[0][0]); scanf("%d", (*(a+0)+0));
4.3、数组万能拆解法
任意的数组,不管有多复杂,其定义都由两部分组成
第一部分:说明数组名和元素个数
第二部分:说明数组元素的类型,可以是任意类型
int a[5]; //第一部分:a[5]
第二部分:int //整型 数组
int b[3][5];
//第一部分:b[3]
第二部分:int [5]
int c[3][4][5];
//第一部分:c[3]
第二部分:int [4][5]
第三部分:int [5]
int *d[5];
//第一部分:d[5]
第二部分:int * //指针 数组
int (*p[5])(int, float); //
第一部分:p[5]
第二部分:int (*)(int, float);
//函数指针 数组 //指针函数
int *func(int, float); 返回值是指针的函数
//函数指针int (*p)(int, float); 用来存放函数的入口地址
以上示例中:a[5],b[3],c[3],d[5],p[5]在本质上并无区别,他们均是数组
以上示例中:a[5],b[3],c[3],d[5],p[5]唯一的不同,是它们所存放的元素的不同
第一部分的声明语句,如果由多个单词组成,C语言规定需要将其拆散写道第二部分的两边
4.4、二维数组的传参
// void func1(int a1[][3]) //可以
void func1(int a1[2][3]) //以数组的方式接收 //
void func1(int a1[2][]) //错的 //
void func1(int a1[][])//错的
区别:
*a1[3]:指针数组,表示数组存放的是指针
(*a1)[3]:数组指针,表示用来存放数组的地址