在C语言中,数组是一种非常重要的数据结构,用于存储多个相同类型的元素。数组可以看作是一个容器,其中的每个元素都有一个固定的内存位置,并且可以通过索引来访问。数组的主要优点是能够高效地存储和访问大量数据,同时支持随机访问,即通过索引快速定位到任意元素。
数组在程序设计中有着广泛的应用,例如存储一组数据、实现队列或栈等数据结构,以及处理矩阵运算等。数组的使用需要掌握其基本概念、创建、初始化、访问和内存布局等知识点。
一维数组是最简单的数组形式,它在内存中是一块连续的存储区域,用于存储相同类型的元素。创建一维数组的基本语法如下:
类型名 数组名[数组长度];
例如,创建一个长度为5的整型数组:
int arr[5];
这里,arr
是数组名,5
是数组的长度,表示数组可以存储5个整型元素。数组的长度必须是正整数,且在定义时不能省略。
数组在创建时可以同时进行初始化,即将数组的每个元素赋予初始值。初始化的方式有以下几种:
逐个赋值初始化:在定义数组时,通过大括号{}
逐个为数组元素赋值。例如:
int arr[5] = {1, 2, 3, 4, 5};
这种方式要求初始化列表中的元素个数与数组长度一致。如果初始化列表中的元素个数少于数组长度,则剩余的元素会被自动初始化为0。
部分初始化:如果初始化列表中的元素个数少于数组长度,剩余的元素会被自动初始化为0。例如:
int arr[5] = {1, 2};
此时,arr[0] = 1
,arr[1] = 2
,而arr[2]
、arr[3]
和arr[4]
都会被初始化为0。
默认初始化:如果在定义数组时没有提供初始化列表,则数组的元素会被自动初始化为0(对于全局数组)或保留内存中的垃圾值(对于局部数组)。例如:
int arr[5];
对于局部数组arr
,其元素值是不确定的;而对于全局数组,其元素会被初始化为0。
数组元素可以通过索引访问,索引从0开始。例如,访问数组arr
的第一个元素可以使用arr[0]
,访问第二个元素可以使用arr[1]
,以此类推。
int arr[5] = {1, 2, 3, 4, 5};
printf("第一个元素:%d\n", arr[0]); // 输出1
printf("第二个元素:%d\n", arr[1]); // 输出2
在实际应用中,经常需要对数组中的每个元素进行操作,例如求和、查找最大值等。可以通过循环语句遍历数组。例如,计算数组arr
中所有元素的和:
int arr[5] = {1, 2, 3, 4, 5};
int sum = 0;
for (int i = 0; i < 5; i++) {
sum += arr[i];
}
printf("数组元素之和:%d\n", sum); // 输出15
数组可以作为函数的参数传递。当数组作为参数传递时,实际上是传递数组的首地址。因此,函数可以通过指针操作数组中的元素。例如,编写一个函数用于计算数组的平均值:
double average(int arr[], int length) {
int sum = 0;
for (int i = 0; i < length; i++) {
sum += arr[i];
}
return (double)sum / length;
}
int main() {
int arr[5] = {1, 2, 3, 4, 5};
printf("数组的平均值:%f\n", average(arr, 5));
return 0;
}
一维数组在内存中是连续存储的。例如,对于一个整型数组int arr[5]
,其在内存中的存储如下:
内存地址 | arr[0] | arr[1] | arr[2] | arr[3] | arr[4] |
---|---|---|---|---|---|
0x1000 | 1 | 2 | 3 | 4 | 5 |
数组的首地址是数组的第一个元素的地址,可以通过&arr[0]
或arr
获取。数组的每个元素占用的内存大小取决于数组的类型。例如,int
类型通常占用4个字节,因此arr[1]
的地址是arr[0]
的地址加上4个字节。
sizeof
计算数组元素个数sizeof
运算符可以用来计算数组的总字节数。通过sizeof
运算符,可以方便地计算数组的长度。例如:
int arr[5];
printf("数组的总字节数:%zu\n", sizeof(arr)); // 输出20
printf("数组的元素个数:%zu\n", sizeof(arr) / sizeof(arr[0])); // 输出5
这里,sizeof(arr)
计算的是整个数组的字节数,sizeof(arr[0])
计算的是数组中每个元素的字节数。通过两者的比值,可以得到数组的元素个数。
二维数组可以看作是一个表格,其中的每个元素可以通过两个索引来访问。创建二维数组的基本语法如下:
类型名 数组名[行数][列数];
例如,创建一个3行4列的整型二维数组:
int arr[3][4];
这里,3
表示数组的行数,4
表示数组的列数,表示数组可以存储3×4=12个整型元素。
二维数组的初始化方式与一维数组类似,可以通过大括号{}
逐个为数组元素赋值。例如:
int arr[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
这种方式要求初始化列表中的元素个数与数组的总元素个数一致。如果初始化列表中的元素个数少于数组的总元素个数,则剩余的元素会被自动初始化为0。
也可以部分初始化二维数组。例如:
int arr[3][4] = {
{1, 2},
{5, 6},
{9, 10}
};
此时,arr[0][0] = 1
,arr[0][1] = 2
,arr[1][0] = 5
,arr[1][1] = 6
,arr[2][0] = 9
,arr[2][1] = 10
,而其他元素都会被初始化为0。
二维数组的元素可以通过两个索引访问,第一个索引表示行,第二个索引表示列。例如,访问二维数组arr
的第一行第二列的元素可以使用arr[0][1]
。
int arr[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
printf("第一行第二列的元素:%d\n", arr[0][1]); // 输出2
可以通过嵌套循环语句遍历二维数组。例如下面代码所示,计算二维数组arr
中所有元素的和:
int arr[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
int sum = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
sum += arr[i][j];
}
}
printf("二维数组元素之和:%d\n", sum); // 输出78
二维数组也可以作为函数参数传递。由于二维数组在内存中是连续存储的,因此可以通过指针操作二维数组中的元素。不过,传递二维数组时需要注意数组的行和列的大小。例如,编写一个函数用于计算二维数组的对角线元素之和:
int diagonalSum(int arr[][4], int rows) {
int sum = 0;
for (int i = 0; i < rows; i++) {
sum += arr[i][i]; // 主对角线元素
}
return sum;
}
int main() {
int arr[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
printf("主对角线元素之和:%d\n", diagonalSum(arr, 3));
return 0;
}
在传递二维数组时,必须指定数组的列数(即arr[][4]
),因为编译器需要通过列数来计算每个元素的内存偏移量。
二维数组在内存中也是连续存储的,但存储方式是按行优先的。这意味着二维数组的每一行会被连续存储在内存中,行与行之间也是连续的。例如,对于一个3行4列的二维数组int arr[3][4]
,其在内存中的存储如下:
内存地址 | arr[0][0] | arr[0][1] | arr[0][2] | arr[0][3] | arr[1][0] | arr[1][1] | arr[1][2] | arr[1][3] | arr[2][0] | arr[2][1] | arr[2][2] | arr[2][3] |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0x1000 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
二维数组的首地址是数组的第一个元素(arr[0][0]
)的地址,可以通过&arr[0][0]
或arr
获取。二维数组的每个元素占用的内存大小取决于数组的类型。例如,int
类型通常占用4个字节,因此arr[1][0]
的地址是arr[0][0]
的地址加上4×4个字节(因为每行有4个元素)。