一、数组的概念
数组是多个相同类型元素的集合。从这个概念中,我们不难看出:
·数组可以存放一个或多个数据,但不能为零
·数组中存放的多个数据,但是它们的类型是相同的。
数组一般被分为一维数组和多维数组,而多维数组中较多用的是二维数组。
二、一维数组的创建和初始化
1.一维数组的创建
一维数组的创建基本语法如下:
type arr_name[常量值]
存放在数组当中的值被称为数组的元素,数组在创建时可以指定数组的大小和元素的类型。
·type指的是数组中元素的数据类型,可以是:char,int,float等,也可以是自定义类型。
·arr_name指的是数组的名字,这个名字可以随意取,可以根据自己的需要。
·[]中的常量值是用来指定数组的大小的,这个大小也是根据自己的需求来决定。
练习:
用一维数组来存储某个班级20人的数学成绩。
此时我们可以这样:
int math[20];
当然,我们在创建数组时也可以创建其他类型的数组:
double score[30];
char ch[99];
2.一维数组的初始化
当我们在创建数组时,需要给数组中的元素一些初始值,这个过程被称为数组的初始化。
那么我们如何进行初始化呢?初始化一共有三种,具体语法如下:
//完全初始化
int arr1[5] = { 1,2,3,4,5 };
//不完全初始化
int arr2[6] = { 1 };//不完全初始化时,未被初始化的元素默认为0
//错误的初始化,初始化的项过多
int arr3[7] = { 1,2,3,4,5,6,7,8 };
return 0;
3.数组的类型
数组也是有类型的,数组算是一种自定义类型,去掉数组名,剩下的就是数组的类型。
如下:
arr1数组的类型是int [5]
arr2数组的类型是int [6]
arr3数组的类型是int [7]
三、数组的使用
我们已经学习了数组的一些基本语法,数组可以存放一堆数据,对数据进行操作,那么我们要如何使用一维数组呢?
1.数组的下标
C语言中规定了数组是有下标的,下标从0开始,第n个元素的下标为n-1,下标就是数组的编号,如下:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
C语言还为我们提供了一个操作符[],叫做下标引用操作符。
这个操作符,用于访问数组的元素。例如,我要访问上述数组中下标为7的元素,就可以这样:
arr[7],如果要访问下标为3的元素,则可以:arr[3],如下代码:
int main()
{
int arr[5] = { 1,2,3,4,5 };
printf("%d\n", arr[1]);
printf("%d\n", arr[3]);
return 0;
}
输出结果:
2.数组的打印
如果我们需要访问数组的所有元素,怎么办呢?
只要我们使用for循环就能轻松搞定:
int main()
{
int arr[5] = { 1,2,3,4,5 };
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
四、数组在内存中的存储
有了上面的知识储备,我们使用数组基本没有障碍了,但是想要深入了解数组,还需要了解一下数组在内存中的存储。
依次打印数组元素的地址:
int main()
{
int arr[5] = { 1,2,3,4,5 };
int i = 0;
for (i = 0; i < 5; i++)
{
printf("&arr[%d] = %p\n", i, &arr[i]);
}
return 0;
}
输出结果为:
根据输出结果我们判断,在数组中,随着下标的增长,地址是由小到大均匀变化的,每两个相邻的元素之间相差4(因为一个整数是4个字节)。所以,我们得出结论:
数组在内存中是连续存放的。
这为我们后期使用指针访问数组奠定了基础
五、sizeof计算元素个数
在使用数组时我们经常会需要用到数组中元素的个数,那么C语言中有办法可以用程序计算元素的个数吗?
其实是可以的,只要使用sizeof
sizeof是C语言中的一个关键字,是可以计算变量或类型的大小的,当然也可以计算数组的大小。
例如:
int main()
{
int arr[5] = { 1,2,3,4,5 };
int i = 0;
printf("%d\n",sizeof(arr));
return 0;
}
结果是20,是数组所占空间的总大小,单位是字节。
我们知道同一个数组中不同元素的大小是相同的,因此,我们只要计算出一个元素的大小和所有元素的大小,再相除就可以得到数组中元素的个数:
int main()
{
int arr[5] = { 1,2,3,4,5 };
int i = 0;
printf("%lld\n", sizeof(arr) / sizeof(arr[0]));
return 0;
}
这里的结果是5,表示数组中有5个元素。
以后在编写代码时,需要数组的个数的地方就不会被写死了,只要数组变化,计算的结果也会跟着变。
六、二维数组的创建
1.二维数组的概念
前面学习了一维数组,数组中的元素类型为内置类型的,如果我们把一维数组作为数组的元素,那么得到的数组就叫做二维数组,以此类推,以二维数组作为元素的数组为三维数组......,二维数组以上的数组统称为多维数组。
2.二维数组的创建
二维数组创建的语法如下:
type arr_name[常量值1] [常量值2]
例如:
int arr [3] [5]
double data[2] [8]
解释:
·3代表数组中有3行
·5代表数组中有5列
·int是数组中每个元素类型为整型类型
·arr是数组名,可以自己指定
七、二维数组的初始化
在创建二维数组时,给定一些数值,这个过程叫做初始化
二维数组的初始化与一维数组基本相同:
1.不完全初始化
int arr1[3] [5] = {1,2}
int arr2[2] [8] = {0}
2.完全初始化
int arr3[3] [5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7}
3.按照行初始化
int arr4[3] [5] = {{1,2},{3,4},{5,6}}
八、二维数组的使用
1.二维数组的下标
我们已经掌握了二维数组的创建和初始化,那么我们应该如何使用二维数组呢?
其实二维数组的访问也是使用下标的形式的,二维数组是有行和列的,只要锁定了行和列,就能锁定一个元素。
C语言规定,二维数组的行和列都是从0开始的,如图所示:
int arr[3] [5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7}
右侧的绿色数字表示行号,上侧的蓝色数字表示列号,都是从0开始,比如:第2行第4列,我们就可以快速定位出7:
int main()
{
int arr[3][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7 };
int i = 0;
printf("%d\n", arr[2] [4]);
return 0;
}
运行结果:
2.二维数组的输入和输出
我们知道了如何访问单个二维数组,那么如何访问整个二维数组呢?
其实只要再利用for循环的嵌套就可以做到:
int main()
{
int arr[3][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7 };
int i = 0, m = 0;
for (i = 0; i < 3; i++)
{
for (m = 0; m < 5; m++)
{
printf("%d ", arr[i][m]);
}
printf("\n");
}
return 0;
}
输出结果:
九、二维数组的存储
类似于一维数组,想研究二维数组的存储方式,我们也是可以打印出所有元素的地址的,代码如下:
int main()
{
int arr[3][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7 };
int i = 0, m = 0;
for (i = 0; i < 3; i++)
{
for (m = 0; m < 5; m++)
{
printf("arr[%d] [%d] = %p\n", i, m ,&arr[i] [m]);
}
}
return 0;
}
运行结果如下:
从输出结果来看,相邻的两个元素之间的地址依然是差了4个字节,即使跨越了一行,也是相差4个字节。所以,二维数组的每个元素也是连续存放的:
了解二维数组在内存中的布局,有利于后续指针的练习。
十、C99中的变长数组
在C99之前,指定数据的大小只能用常量、常量表达式,或者初始化数据时,可以省略数组的大小:
int arr1[10]
in aee2[3+5]
int aee3[] = {1,2,3}
这样的语法限制,使创建数组时不够灵活,有时候数组大了又浪费空间,数组小了又不够用。
在C99中给出了变长数组的新特性,允许我们使用变量来指定数组的大小。
例如:
int n = a + b;
int arr[n];
上面的示例中,arr就是变长数组,因为它的长度取决于变量n的值,但是编译器无法事先确定,只能运行时才能知道n是多少。
变长数组的特征,就是只有运行了程序才知道它的长度,所以变长数组不能初始化。
它的好处是让程序员在开发时,不用估计数组的长度,可以在运行时具体分配适合的长度
ps:变长数组的意思是数组的长度可以用变量来指定,并不是说数组的大小可以改变,数组的大小在程序运行时就已经确定了。
遗憾的是,目前在vs2022上不支持变长数组,没法测试,以后有机会我会再来测试的。
十一、数组练习
练习1:多个字符从两端移动,向中间汇聚
演示代码:
int main()
{
char arr1[] = "hello world!";
char arr2[] = "************";
int left = 0;
int right = strlen(arr2)-1;
while (left <= right)
{
arr2[left] = arr1[left];
arr2[right] = arr1[right];
left++;
right--;
printf("%s\n", arr2);
Sleep(1000);
system("cls");
}
printf("%s\n", arr2);
return 0;
}
练习2:二分查找
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10};
int right = sizeof(arr) / sizeof(arr[0]) - 1;
int left = 0;
int key = 7;
int flag = 0;
int mid = 0;
scanf("%d", &key);
while (right >= left)
{
mid = (right + left) / 2;
if (key > arr[mid])
{
left = mid + 1;
}
else if (key < arr[mid])
{
right = mid - 1;
}
else
{
flag++;
break;
}
}
if (flag)
{
printf("找到了,下标是%d", mid);
}
else
{
printf("找不到");
}
return 0;
}