目录
1.数组的概念
数组是一组相同类型元素的集合
-
数组中存放的是1个或者多个数据,但是数组元素个数不能为0。
-
数组中存放的多个数据,类型是相同的。
数组分为⼀维数组和多维数组,多维数组⼀般⽐较多⻅的是⼆维数组。
2.一维数组
2.1.一维数组的创建和初始化
2.1.1.数组声明
格式:数据类型 数组名[元素个数]
int scores[5]; // 声明包含5个整数的数组
float temperatures[7]; // 声明包含7个浮点数的数组
此时数组元素值不确定(包含内存残留数据)
2.1.2.初始化方式
2.1.2.1.完全初始化
int primes[5] = {2, 3, 5, 7, 11};
char vowels[] = {'a', 'e', 'i', 'o', 'u'}; // 自动推导长度为5
2.1.2.2.部分初始化
int arr[5] = {10,20}; // 剩余元素自动补0
// 结果为:[10,20,0,0,0]
2.1.2.3.特殊初始化技巧
- 字符串数组
char greeting[] = "Hello"; // 等价于 {'H','e','l','l','o','\0'}
- 指定位置初始化(C99+)
int arr[6] = {[3] = 9, [5] = 20};
// 结果为:[0,0,0,9,0,20]
2.2.一维数组的使用
2.2.1. 数组下标
数组元素通过下标访问,下标从0开始计算:
int scores[5] = {85, 90, 78, 92, 88};
// 索引: 0 1 2 3 4
printf("%d", scores[2]); // 输出第三个元素78
注意:数组越界访问(如scores[5])会导致未定义行为
2.2.2.数组元素打印
使用循环结构遍历数组:
#include <stdio.h>
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("%d ", arr[i]);
}
return 0;
}
输出:
2.2.3.数组输入
#include <stdio.h>
int main(){
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int i = 0;
for(i = 0; i < 10; i++){
scanf("%d", &arr[i]);
}
for(i = 0; i < 10; i++){
printf("%d ", arr[i]);
}
return 0;
}
2.3.一维数组在内存中的存储
依次打印数组元素的地址:
#include <stdio.h>
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] = %p\n ", i, &arr[i]);
}
return 0;
}
我们看看输出结果:
从输出的结果我们分析,数组随着下标的增⻓,地址是由⼩到⼤变化的,并且我们发现每两个相邻的元素之间相差4(因为⼀个整型是4个字节)。所以我们得出结论:数组在内存中是连续存放的。
3.sizeof计算数组元素个数
sizeof
中C语⾔是⼀个关键字,是可以计算类型或者变量⼤⼩的,其实
sizeof
也可以计算数组的
⼤⼩。
⽐如:
#include <stido.h>
int main(){
int arr[10] = {0};
printf("%d\n", sizeof(arr));
return 0;
}
输出的结果是40,计算的是数组所占内存空间的总⼤⼩,单位是字节。
⼜知道数组中所有元素的类型都是相同的,那只要计算出⼀个元素所占字节的个数,数组的元素
个数就能算出来。
#include <stido.h>
int main(){
int arr[10] = {0};
printf("%d\n", sizeof(arr[0]));//计算⼀个元素的⼤⼩,单位是字节
return 0;
}
接下来就能计算出数组的元素个数:
#include <stido.h>
int main(){
int arr[10] = {0};
int sz = sizeof(arr)/sizeof(arr[0]);
printf("%d\n", sz);
return 0;
}
输出结果是:10,表⽰数组有10个元素。
4.二维数组
4.1.二维数组的创建
前⾯学习的数组被称为⼀维数组,数组的元素都是内置类型的,如果我们把⼀维数组作为数组的元
素,这时候就是⼆维数组,⼆维数组作为数组元素的数组被称为三维数组,⼆维数组以上的数组统称为多维数组

4.2.二维数组的初始化
4.2.1.不完全初始化
int arr1[3][5] = {1, 2};
int arr2[3][5] = {0};
4.2.2.完全初始化
int arr3[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
4.2.3. 按照行初始化
intarr4[3][5]={{1,2},{3,4},{5,6}};
4.2.4.初始化时省略行,但是不能省略列
intarr5[][5]={1,2,3};
intarr6[][5]={1,2,3,4,5,6,7};
intarr7[][5]={{1,2},{3,4},{5,6}};
4.3.二维数组的使用
4.3.1.二维数组的下标
访问格式:数组名[行下标][列下标]
如对于:
int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
第2⾏,第4列,就能快速定位出7。
#include <stdio.h>
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[2][4]);
return 0;
}
输出:
4.3.2.二维数组的输入和输出
- 方法1:逐元素输入
for(int i=0; i<3; i++){
for(int j=0; j<4; j++){
scanf("%d", &matrix[i][j]);
}
}
- 方法2:按行输入
for(int i=0; i<3; i++){
scanf("%d %d %d %d", &matrix[i][0], &matrix[i][1],
&matrix[i][2], &matrix[i][3]);
}
- 输出方法
for(int i=0; i<3; i++){
for(int j=0; j<4; j++){
printf("%4d", matrix[i][j]); // 每个元素占4字符宽度
}
printf("\n"); // 换行输出下一行
}
4.4.二维数组在内存中的存储
打印出数组所有元素的地址:
#include <stdio.h>
int main(){
int arr[3][5] = { 0 };
int i = 0;
int 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]);
}
}
return 0;
}
输出结果:
从输出的结果来看,每⼀⾏内部的每个元素都是相邻的,地址之间相差4个字节,跨⾏位置处的两个元素(如:arr[0][4]和arr[1][0])之间也是差4个字节,所以⼆维数组中的每个元素都是连续存放的。
如下图所⽰:

了解清楚⼆维数组在内存中的布局,有利于我们后期使⽤指针来访问数组的学习。
5.C99变长数组(VLA)详解
5.1. 基本定义
变长数组(Variable-Length Array)允许在程序运行时确定数组长度,其声明语法为:
int n = 10;
int arr[n]; // 合法VLA声明
5.2. 核心特性
- 动态尺寸:数组维度可以是任意整型表达式
void func(int size) { double buffer[size*2]; // 使用参数计算数组大小 }
- 存储分配:分配在栈内存空间
- 生存周期:与自动变量相同,离开作用域自动释放
5.3. 关键限制
- 禁止静态存储:
static int vla[10]; // 错误:静态存储期变量不能是VLA
- 禁止初始化列表:
int n = 5; int arr[n] = {0}; // 错误:VLA不能初始化
- 函数参数限制:
void foo(int arr[][n]); // 错误:n必须先于数组声明
5.4. 多维数组应用
支持多维动态数组:
int rows = 3, cols = 4;
int matrix[rows][cols]; // 二维VLA
// 动态初始化示例
for(int i=0; i<rows; i++){
for(int j=0; j<cols; j++){
matrix[i][j] = i*j;
}
}
5.5. 特殊运算
- sizeof运算符:运行时计算实际大小
int n = 5; printf("%zu", sizeof(int[n])); // 输出20(假设int为4字节)
5.6. 工程实践建议
- 适用场景:临时缓冲区、算法中的中间存储
- 风险控制:避免超大尺寸导致栈溢出
- 替代方案:超过1KB建议使用动态内存分配
int* safe_array = malloc(n * sizeof(int));
5.7. 标准演进
- C99:强制支持
- C11:改为可选特性(__STDC_NO_VLA__宏标识)
- C17:维持可选特性
典型应用示例:矩阵运算
void matrix_mult(int m, int n, int p,
int A[m][n], int B[n][p], int C[m][p]) {
for(int i=0; i<m; i++){
for(int j=0; j<p; j++){
C[i][j] = 0;
for(int k=0; k<n; k++){
C[i][j] += A[i][k] * B[k][j];
}
}
}
}
6.数组练习
-
练习1:多个字符从两端移动,向中间汇聚
#include <stdio.h>
int main(){
char arr1[] = "welcome to bit...";
char arr2[] = "#################";
int left = 0;
int right = strlen(arr1)-1;
printf("%s\n", arr2);
while(left<=right){
Sleep(1000);
arr2[left] = arr1[left];
arr2[right] = arr1[right];
left++;
right--;
printf("%s\n", arr2);
}
return 0;
}
-
练习2:⼆分查找
给定⼀个升序的整型数组,在这个数组中查找到指定的值n,找到了就打印n的下标,找不到就
打印:"找不到"。
#include <stdio.h>
int main(){
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");
return 0;
}
求中间元素的下标,使⽤
mid = (left + right) / 2
,如果left和right⽐较⼤的时候可能存在
问题,可以使⽤下⾯的⽅式:
mid = left + (right - left) / 2;