一、数组核心概念
数组是一组相同类型元素的集合,核心特征有二:一是元素个数≥1,二是所有元素类型一致。数组分为一维数组和多维数组(常用为二维数组),是 C 语言中存储批量同类型数据的基础结构。
二、一维数组
1. 创建与初始化
-
创建语法:
type arr_name[常量值];,其中type为元素类型(如int、char等),arr_name为数组名,[]内常量值指定数组大小。示例:int math[20];(存储 20 个数学成绩)。 -
初始化方式:
- 完全初始化:
int arr[5] = {1,2,3,4,5};(所有元素明确赋值)。 - 不完全初始化:
int arr2[6] = {1};(仅首元素赋值,剩余默认初始化为 0)。 - 错误示例:
int arr3[3] = {1,2,3,4};(初始化项数量超过数组大小)。
- 完全初始化:
-
数组类型:去掉数组名后的部分即为数组类型,如
int arr[10]的类型是int [10]。
2. 使用方法
-
下标访问:数组下标从 0 开始,最后一个元素下标为
n-1(n为元素个数),通过[](下标引用操作符)访问,示例:arr[3]访问下标为 3 的元素。 -
遍历操作:通过
for循环生成所有下标,实现数组元素的打印或输入。- 打印示例:循环
i从0到n-1,输出arr[i]。
- 打印示例:循环
int arr[]={1,2,3,4,5,6,7,8,9,10}; //0-9
for(int i=0;i<10;i++){
printf("%d ",arr[i]);
}
-
- 输入示例:循环
i从0到n-1,通过scanf("%d", &arr[i])赋值。
- 输入示例:循环
int arr[10]={};
int i=0;
for( i=0;i<10;i++){
scanf("%d ",&arr[i]);
printf("%d ",arr[i]);
}
3. 内存存储特性
数组元素在内存中连续存放,下标增长时地址由小到大递增,相邻元素地址差等于元素类型所占字节数(如int数组相邻元素差 4 字节),为指针访问数组奠定基础。
int arr1[10]={ 0 };
char arr2[10]={0};
printf("%zd\n",sizeof(arr1));//40
printf("%zd\n",sizeof(int[5]));//20
//&p-专门打印地址
int arr[10]={1,2,3,4,5,6,7,8,9,10};
int i=0;
int sz= sizeof(arr)/sizeof(arr[0]);
for( i=0;i<sz;i++){
printf("&arr[%d]= %p\n",i,&arr[i]); //&取地址,%p 十六进制
// &arr[0]= 0062fea0 两个之间差4
// &arr[1]= 0062fea4 数组在内存中是连续存放的
// &arr[2]= 0062fea8 随着下标的增长,地址是由小到大变化的
// &arr[3]= 0062feac
// &arr[4]= 0062feb0
// &arr[5]= 0062feb4
// &arr[6]= 0062feb8
// &arr[7]= 0062febc
// &arr[8]= 0062fec0
// &arr[9]= 0062fec4
}
4. 元素个数计算
使用sizeof关键字计算:数组元素个数 = sizeof(数组名) / sizeof(数组首个元素),示例:int sz = sizeof(arr)/sizeof(arr[0]);,该方法可灵活适配数组大小变化。
int arr[10]={0};
printf("%zd\n",sizeof(arr));//40
printf("%zd\n",sizeof(arr[0]));//4
printf("%zd\n",sizeof(arr)/sizeof(arr[0]));//计算元素个数
三、二维数组
1. 概念与创建
- 概念:以一维数组为元素的数组,本质是 “数组的数组”,常用于表示表格类数据。
- 创建语法:
type arr_name[常量值1][常量值2];,其中常量值1表示行数,常量值2表示列数。示例:int arr[3][5];(3 行 5 列的整型二维数组)。
2. 初始化方式
- 不完全初始化:
int arr1[3][5] = {1,2};(按顺序赋值,未赋值元素默认 0)。 - 完全初始化:
int arr3[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};(依次填满所有元素)。 - 按行初始化:
int arr4[3][5] = {{1,2},{3,4},{5,6}};(每行元素用大括号分隔,未赋值元素默认 0)。 - 省略行不省略列:
int arr5[][5] = {1,2,3};(编译器可根据列数和元素个数自动计算行数)。
3. 使用方法
- 下标访问:行下标和列下标均从 0 开始,通过
arr[行号][列号]锁定元素,示例:arr[2][4]访问第 3 行第 5 列元素。 - 遍历操作:嵌套
for循环,外层循环控制行号,内层循环控制列号,实现输入或输出。
int arr[3][5]={{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}} ;
int i=0,j=0;
for(i=0;i<3;i++){ //行
for(j=0;j<5;j++){ //列
scanf("%d ",&arr[i][j]);
printf("%d ",arr[i][j]);
}
printf("\n");
}
4. 内存存储特性
二维数组的所有元素在内存中连续存放,不仅同一行内元素相邻(地址差为元素类型字节数),跨行元素(如arr[0][4]与arr[1][0])也相邻,地址连续递增。
//把数组每个元素地址打印出来
int arr[3][5]={0} ;
int i=0,j=0;
for(i=0;i<3;i++){ //行
for(j=0;j<5;j++){ //列
printf("&arr[%d][%d] =%p\n",i,j,&arr[i][j]);
}
}
// &arr[0][0] =0062fe8c
// &arr[0][1] =0062fe90
// &arr[0][2] =0062fe94
// &arr[0][3] =0062fe98
// &arr[0][4] =0062fe9c
// &arr[1][0] =0062fea0
// &arr[1][1] =0062fea4
// &arr[1][2] =0062fea8
// &arr[1][3] =0062feac
// &arr[1][4] =0062feb0
// &arr[2][0] =0062feb4
// &arr[2][1] =0062feb8
// &arr[2][2] =0062febc
// &arr[2][3] =0062fec0
// &arr[2][4] =0062fec4
四、C99 变长数组(VLA)
- 特性:C99 标准新增,允许使用变量指定数组大小,数组长度在程序运行时确定(非编译时),但大小确定后不可修改,且不能初始化。
- 语法示例:
int n = 5; int arr[n];(n为变量,数组大小由运行时输入或计算决定)。 - 注意:VS2022 不支持该特性,GCC 等编译器可正常使用。
//C99变长数组
int n = 0;
scanf("%d", &n);//根据输入数值确定数组的大小
int arr[n];
int i = 0;
for (i = 0; i < n; i++)
{
scanf("%d", &arr[i]);
}
for (i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
五、数组实战练习
1. 字符两端汇聚
通过left(左指针)和right(右指针)从数组两端向中间移动,逐步替换目标字符,结合Sleep函数实现动态演示效果。
char arr1[] = "welcome to bit..."; //两个数组长度一样
char arr2[] = "#################";
int left = 0;
int right = strlen(arr1)-1;
printf("%s\n", arr2);
while(left<=right)
{
Sleep(1000); //需要<windows.h> 1000ms
arr2[left] = arr1[left];
arr2[right] = arr1[right];
left++; //left往后走
right--; //right往前走
printf("%s\n", arr2);
}
// #################
// w###############.
// we#############..
// wel###########...
// welc#########t...
// welco#######it...
// welcom#####bit...
// welcome### bit...
// welcome #o bit...
// welcome to bit...
2. 二分查找(折半查找)
-
适用场景:有序(升序 / 降序)数组中查找指定元素,效率远高于遍历。
-
核心逻辑:
- 定义
left(左边界下标)、right(右边界下标,初始为数组最后一个元素下标)。 - 计算中间下标
mid = left + (right - left)/2(避免left+right溢出)。 - 比较
arr[mid]与目标值:大于目标值则调整右边界right = mid-1,小于则调整左边界left = mid+1,等于则找到目标。 - 循环终止条件:
left > right(未找到)或找到目标元素。
- 定义
int arr[] = {1,2,3,4,5,6,7,8,9,10};
int left = 0;
int right = sizeof(arr)/sizeof(arr[0])-1;
int key = 7;//要找的数字
int mid = 0;//记录中间元素的下标
int find = 0;
while(left<=right)
{
mid = (left+right)/2;
if(arr[mid]>key)
{
right = mid-1;
}
else if(arr[mid] < key)
{
left = mid+1;
}
else
{
find = 1;
break;
}
}
if(1 == find )
printf("找到了,下标是%d\n", mid);
else
printf("找不到\n");