数组的概念
数组是一组相同类型元素的集合;
- 数组中存放的是1个或多个数据,但是数组元素个数不能为 0 。
- 数组中存放的多个数据,类型是相同的。
数组可以分为一维数组,多维数组;常见的是二维数组。
一维数组
创建和初始化
ini
type arr_name[常量值];
数组类型 数组名称[元素个数];
存放在数组的值被称为数组的元素,数组在创建的时候可以指定数组的大小和数组的元素类型。
数组的创建
ini
int math[20];
数组的初始化
csharp
int main()
{
int num[5] = {1,2,3,4,5};//完全初始化:创建数组,并且初始化1,2,3,4,5
int num2[5] = {1,2,3};//不完全初始化,剩余的元素初始化为 0
int num3[] = {1,2,3};//如果数组初始化了,是可以省略数组大小
//数组的大小,编译器根据初始化的内容确定
int num4[5] = {1,2,3,4,5,6};//报错
return 0;
}
数组的类型
数组属于自定义类型。
csharp
int main()
{
int num[5] = {1,2,3,4,5}; //num1的类型是 int [5]
int num2[10] = {1,2,3}; //num2的类型是 int [10]
int num3[] = {1,2,3};
return 0;
}
一维数组的使用
数组下标
arduino
int arr[10] = {1,2,3,4,5,6,7,8,9,10};//对应的下标是 0 ~ 9
- 下标是从0开始,最后一个元素的下标是n-1
- C 语言中使用下标访问数组中的数据
- 为下标访问操作符
ini
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
//打印 7
printf("%d\n", arr[6]);
int i = 0;
//循环打印所有数组
for (i = 0; i < 10;i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
执行结果
C99标准之前,数组的大小只能是常量指定
数组在内存中的存储
观察数字在内存中的地址
ini
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
//循环打印所有数组
for (i = 0; i < 10;i++)
{
printf("arr[%d] = %pn",i &arr1[i]);// %p 用来打印地址
}
return 0;
}
执行结果
- 一维数组在内存中是连续存放的
- 随着下标的增长,地址也是增长
sizeof计算数组的长度
c
int main()
{
int arr[10] = { 1,2,3 };//10 * 4
printf("%d\n", sizeof(arr));//sizeof(数组)计算的是数组所占内存空间的大小,单位是字节
printf("%d\n", sizeof(arr[0]));
printf("%d\n", sizeof(arr) / sizeof(arr[0]));
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
//循环打印所有数组
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
执行结果
此时,数组元素个数的变化并不会影响代码的运行。
二维数组的创建初始化
如果把一维数组作为数组的元素,那就是二维数组。
二维数组的创建
ini
type arr_name[常量值1][常量值2];
//例如
int arr [3][5];
- 3 表示数组有 3 行
- 5 表示每一行有 5 个元素
csharp
int main()
{
double score[20][5];
return 0;
}
全初始化
ini
int main()
{
//不完全初始化
int score1[3][5] = {1,2};
int score2[3][5] = {0};
int score3[3][5] = {1,2,3,4,5,6,7};
int score3[3][5] = {{1,2},{3,4},{5,6}};//指定1,2放入第一行,3,4放入第二行;以此类推
//完全初始化
int score4[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
return 0;
}
二维数组初始化时,行可以省略,但是列不能省略
csharp
int main()
{
int score1[][5] = {1,2}; //初始化了一行
int score3[][5] = {1,2,3,4,5,6,7};//初始化了两行
int score3[][5] = {{1,2},{3,4},{5,6}};//初始化了三行
return 0;
}
打印指定数组和所有数组
三行五列的数组:[3][5]
下标 | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 |
1 | 2 | 3 | 4 | 5 | 6 |
2 | 3 | 4 | 5 | 6 | 7 |
ini
int main()
{
int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
printf("%d\n", arr[1][3]);//打印第二行第四个数字 5
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d", arr[i][j]);
}
printf("\n");
}
return 0;
}
执行结果
二维数组在内存中也是连续存放的。
arr1[]
arr2[][]
C99中的变长数组
在C99标准之前,C语言在创建数组的时候,数组大小的指定只能使用常量、常量表达式,或者如果我们初始化数据的话,可以省略数组大小。
如:
ini
int arr1[10];
int arr2[3+5];
int arr3[] = {1,2,3};
C99标准之后,引入了变长数组的概念,允许数组的大小是变量。
arduino
int main()
{
int n = 0;
scanf("%d",&n);
int arr[n];
return 0;
}
- VS虽然支持了C99的语法,但是并不是完全支持。比如变长数组。
- 变长数组不能初始化
变长数组中,变长的概念是数组的长度可以引用变量,而不仅仅使用常量。并不是说数组可以任意改变其大小。
数组练习
多个字符从两端移动,向中间汇聚
打印内容如下:welcome to C !!!!!!!!!!
markdown
//***********************
//w*********************!
//we*******************!!
//以此类推,最终打印
//welcome to C !!!!!!!!!!
代码实现
ini
#include <string.h>
int main()
{
char arr1[] = "welcome to C !!!!!!!!!!";
char arr2[] = "***********************";
int left = 0;
int right = strlen(arr1)-1;
while(left<=right)
{
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n",arr2);
left++;
right--;
}
return 0;
}
执行结果
添加动态效果
- Sleep(1000); //休眠一秒。需要引入头文件,windows.h
在一行上像两端移动
- system("cls");
最终代码
scss
#include <string.h>
int main()
{
char arr1[] = "welcome to C !!!!!!!!!!";
char arr2[] = "***********************";
int left = 0;
int right = strlen(arr1)-1;
while(left<=right)
{
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n",arr2);
Sleep(1000);
system("cls");
left++;
right--;
}
printf("%s\n",arr2);
return 0;
}
动态效果,自行验证。
二分查找
在一个指定的有序数组中查找指定的数字n
,也叫折半查找。
例如:
int arr[] = {1,2,3,4,5,6,7,8,9,10};
int k = 7;
在arr数组中,找 7
遍历查找法
ini
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int k = 0;
scanf("%d", &k);
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
int find = 0;//假设找不到
for (i = 0; i < sz; i++)
{
if (k == arr[i])
{
printf("找到了,下标是%d\n", i);
find = 1;
break;
}
}
if (find == 0)
{
printf("找不到\n");
}
return 0;
}
执行结果
二分查找算法
ini
Mid = (L + R)/2;
- Mid:中间位
- L:最左下标
- R:最右下标
代码
ini
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int k = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
scanf("%d", &k);
//使用二分查找
int left = 0;
int right = sz - 1;
int find = 0;//假设找不到
while (left <= right)
{
//int mid = (left + right) / 2;//这种写法在left和right都非常大,接近int的最大值的时候会有问题.
int mid = left + (right - left) / 2;
if (arr[mid] < k)
{
left = mid + 1;
}
else if (arr[mid] > k)
{
right = mid - 1;
}
else
{
printf("找到了,下标是%d\n", mid);
find = 1;
break;
}
}
if (find == 0)
{
printf("找不到了");
}
return 0;
}
执行结果
注意:
二分查找的前提条件是数组必须是有序的
时间复杂度为O(Log₂n)