C语言 数组
- 一、一维数组
- 1. 数组的创建方式
- 程序清单1
- 程序清单2
- 2. 计算数组的元素的个数
- 3. 数组在内存中的存储方式
- 二、二维数组
- 1. 二维数组的创建方式
- 2. 计算二维数组的行和列
- 3. 二维数组在内存中的存储方式
- 三、数组名的含义
- 总结数组名的应用场景
- 数组名作为函数参数
一、一维数组
1. 数组的创建方式
程序清单1
#include <stdio.h>
int main() {
int arr1[10] = { 1,2,3,4,5 };
int arr2[] = { 1,2,3,4,5 };
int arr3[10];
return 0;
}
数组 arr1 在定义时,长度给了 10,但初始化未完全。
数组 arr2 在定义时,未明确数组大小,底层根据初始化后提供默认大小。
数组 arr3 只被定义,未初始化,所以底层放的都是随机数字。
程序清单2
下面的三个数组呈现了字符数组的区别。
这里需要注意 sizeof 和 strlen 的区别,sizeof 求的是整个数组内所有元素占内存的大小( 包括 \0 ),strlen 求的是字符串长度( \0 之前 )。也就是说,前者求的是数组元素的大小,后者求的是字符串的长度。
#include <stdio.h>
#include <string.h>
int main() {
char arr4[] = "abcd";
char arr5[] = { 'a','b','c','d' };
char arr6[10] = { 'a','b','c','d' };
printf("%d %d\n", sizeof(arr4), strlen(arr4));
return 0;
}
// 输出结果:5 4
2. 计算数组的元素的个数
在 C语言 中,sizeof 可以用来计算某个变量的所占内存的字节大小,所以利用【整个数组所占的内存大小】/ 【数组内某个元素所占的内存大小】,就能够得出数组长度。
#include <stdio.h>
int main() {
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", sizeof(arr)); // 40
printf("%d\n", sizeof(arr[0])); // 4
int size = sizeof(arr) / sizeof(arr[0]); // 求数组长度的方法
printf("%d\n", size); // 10
return 0;
}
3. 数组在内存中的存储方式
#include <stdio.h>
int main() {
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int size = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < size; i++) {
printf("&arr[%d] => %p\n", i, &arr[i]);
}
return 0;
}
输出结果:
从上面的十六进制的地址来看,我们可以得出结论:
① 一维数组在内存中是连续存放的。
② 随着数组下标的增长,地址由低到高变化。
③ 地址之间的差值,即数组元素类型的大小。( 例如:数组存放的元素是整型,那么每个元素的地址之间就相差 4. )
二、二维数组
1. 二维数组的创建方式
#include <stdio.h>
int main() {
int arr1[3][5] = { 0 };
int arr2[3][5] = { 1,2,3,4,5,6 };
int arr3[][5] = {1,2,3,4,5,6};
int arr4[3][5] = { {1,2}, {3,4}, {5,6} };
//int arr[3][] = { {1,2}, {3,4}, {5,6} }; // error
return 0;
}
注意事项:
① 二维数组在创建时,行可以省略,但列不可省略。
② 如果提前知道二维数组中存储什么元素,推荐上面的 arr4 (直接初始化);如果提前不确定二维数组的元素,推荐上面的 arr1. (初始化第一行第一列的元素,后面的自动初始化为 0.)
2. 计算二维数组的行和列
和计算一维数组的大小思想相同,这里依旧先采用 sizeof 计算内存所占大小,之后分别计算行和列。
#include <stdio.h>
int main() {
int arr[3][5] = { {1,2}, {3,4}, {5,6} };
// 整个二维数组的大小 / 第一行一维数组大小
int row = sizeof(arr) / sizeof(arr[0]); // 60/20 = 3
// 第一行一维数组大小 / 第一行第一个数组元素的大小
int column = sizeof(arr[0]) / sizeof(arr[0][0]); // 20/4 = 5
return 0;
}
3. 二维数组在内存中的存储方式
#include <stdio.h>
int main() {
int arr[3][5] = { {1,2}, {3,4}, {5,6} };
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 5; j++) {
printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
}
printf("\n");
}
return 0;
}
输出结果:
从上面的十六进制地址的输出结果来看,我们得出结论:
二维数组在内存中是连续存放的,也就是说实际的内存是连续存放的,和我们想象中的几行几列不一样。
三、数组名的含义
#include <stdio.h>
int main() {
int arr[] = {1,2,3,4,5,6,7,8,9,10};
printf("%p\n", arr);
printf("%p\n\n", arr + 1); // 往后跳 4 个字节
printf("%p\n", &arr[0]);
printf("%p\n\n", &arr[0] + 1); // 往后跳 4 个字节
printf("%p\n", &arr);
printf("%p\n\n", &arr + 1); // 往后跳 40个字节
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr[0]));
//printf("%d", sizeof(&arr); // error
return 0;
}
输出结果:
总结数组名的应用场景
从上面的四组数据来看数组名在不同的场景下,起到不同的作用.
一般情况下,数组名就是数组首元素的地址。但有两个例外:
① 【sizeof(数组名)】,数组名表示整个数组,计算的是整个数组占用内存的大小。
② 【&数组名】,数组名表示整个数组,取出的是整个数组的地址。
数组名作为函数参数
#include <stdio.h>
void test(int arr[]) {
int size = sizeof(arr) / sizeof(arr[0]); // 1 / 1 = 1
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
}
int main() {
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
test(arr); // 传递的实际上是首元素的地址 <==> &arr[0]
return 0;
}
输出结果:(32 位)
现在我们就能理解了,arr 这个数组名作为参数时,即表示数组首元素的地址。所以,本质上,它就相当于传了一个指针变量给 test 函数。思考过后,我们就能够将上面的程序改为下面的程序。
#include <stdio.h>
void test(int* arr, int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
}
int main() {
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int size = sizeof(arr) / sizeof(arr[0]);
test(arr, size); // 传递的实际上是首元素的地址 <==> &arr[0]
return 0;
}
// 输出结果:1 2 3 4 5 6 7 8 9 10
总结两个重要的点:
① arr 数组名作为参数时,传递的是一个指针变量。
② 计算数组的长度不能放在外置函数。