C语言的数组知识
一、一维数组的创建和初始化
1.1 数组的创建:
数组是一组相同类型元素的集合。数组的创建方式:
type_t arr_name [const_n];
// type_t 指数组的元素类型
// arr_name 数组的名称
// const_n 这是一个常量表达式,用来指定数组的大小
数组创建的实例:
int arr01[10];
int i = 10;
int arr02[i]; //数组是否可以正常创建?
float arr03[3];
double a04[50];
注:数组创建的时候,[ ]中要给一个常量才可以,不能使用变量。
1.2 数组的初始化:
数组的初始化是指,在创建数组的时候,给数组的内容同时赋值一些合理初始化值。
int arr1[10] = { 1,2,3 };
int arr2[] = { 1,2,3,4 };
char arr3[3] = { 'a',98,'c' };
char arr4[] = { 'a','b','c' };
char arr5[] = "abcdef";
数组创建的时候,不指定数组大小就可以初始化,数组的元素个数根据初始化的内容来确定。
但是对于下面的代码,要区分内存中如何分配。
char ch1[5] = { 'b','i','t' };
char ch2[] = { 'b','i','t' };
char ch3[] = "bit";
printf("%d\n", strlen(ch1));
printf("%d\n", strlen(ch2));
printf("%d\n", strlen(ch3));
如图,strlen( ) 函数只是计算字符串大小,初始化只有三个字符,为什么中间那个输出15呢?
我们开启调试查看一下三个 ch 字符数组的情况。
- 第一个 ch 字符数组,初始化五个空间,使用三个后,其他没有使用的空间默认 ’ \0 ’ 结束标志,所以计算数组元素个数,显示为3。
- 第二个 ch 字符数组,没有初始化空间,那就根据数组元素个数分配空间。定义三个字符元素,但是没有给出 ’ \0 ’ 结束标志,所以数组计算长度没有及时结束,一直在内存中遇到某个 ’ \0 ’ ,程序才结束。
- 第三个 ch 字符串数组,同样没有初始化空间,但是这里提供的是字符串数组,字符串末尾自带 ’ \0 ’ ,所以正常结束,显示为3。
二、一维数组的使用
对于数组的使用,我们之前介绍了一个操作符:[ ] ,下标引用操作符。它其实就是数组访问的操作符。
//数组的使用
int arr[10] = { 0 }; //数组不完全初始化
//计算数组元素个数
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
//循环赋值
for (i = 0; i < 10; i++) {
arr[i] = i;
}
//输出数组的内容
for (i = 0; i < 10; i++) {
printf("%d", arr[i]);
}
小结:
- 数组是使用下标来访问的,下标是从0开始。
- 数组的大小可以通过计算获得。
三、 一维数组在内容中的存储
接下来我们探讨下数组在内容中的存储。
//数组在内存中的存储
int i = 0;
int arr[10] = { 0 };
for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
printf("&arr[%d] = %p\n", i, &arr[i]);
}
输出结果如下:
仔细观察输出结果,我们会发现:
- 数组的每个元素间距都是相差4,这是因为我们定义的是int类型的数组。
- 随着数组下标的增长,元素的地址,也会有规律的递增。
由此可以得出结论:数组在内存中是连续存放的。
四、二维数组的创建和初始化
4.1 二维数组的创建
-
二维数组是两个[ ],第一个[ ]控制行数,第二个[ ]控制列数(每行上有几个元素)。
-
可以在{ }里面套个{ },用来初始化每列上的元素。
-
可以省略第一个[ ],这样程序会根据第二个[ ]判断每行有几个元素,然后进行初始化。
但是第二个[ ]不能省略。
//二维数组的初始化
int arr1[3][4] = { 1,2,3,4 };
int arr2[3][4] = { {1,2},{3,4} };
int arr3[][4] = { 1,2,3,4 };
int arr4[][4] = { {1,2},{3,4} };
4.2 二维数组的使用
二维数组的使用也是通过下标的方式。
int arr1[3][4] = { 0 };
int i = 0;
//外层for,第一个[]控制行数
for (i = 0; i < 3; i++) {
int j = 0;
//内层for,第二个[]控制列数
for (j = 0; j < 4; j++) {
//二维数组赋值
arr1[i][j] = i * 4 + j;
}
}
//输出二维数组
for (i = 0; i < 3; i++) {
int j = 0;
for (j = 0; j < 4; j++) {
printf("arr1[%d][%d] = %d\n", i, j, arr1[i][j]);
}
}
五、 二维数组在内存中的存储
像一维数组一样,我们尝试打印二维数组的每个元素。
//二维数组在内层中的存储
int arr[3][4];
int i = 0;
for (i = 0; i < 3; i++) {
int j = 0;
for (j = 0; j < 4; j++) {
printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
}
}
我们取二维数组地址输出,发现二维数组在内存中存储的地址也是连续的。
所以二维数组也是线性存储的,不是像矩阵那样有行有列。
六、数组作为函数参数
我们在编写代码的时候,有时候会把数组作为参数传递给函数,例如:我们现在要实现一个冒泡排序的函数,能把一个整型数组排序。
冒泡排序:把一个乱序的数组进行排序。
将数组的第一个元素和第二个元素对比,如果第一个元素比第二个大,就交换位置;然后第二个位置的元素和第三个位置的元素比较,前一个大就交换位置…一直到走完这一趟,会发现数组最后一个元素是数组中最大的元素。接下来就是下一趟比较,重复上述操作…
动图演示:
了解了冒泡排序,让我们回到数组作为函数参数,设计个能完成冒泡排序的函数。
6.1 冒泡排序函数的错误设计
//方法1:
#include <stdio.h>
void bubble_sort(int arr[])
{
int sz = sizeof(arr)/sizeof(arr[0]);//这样对吗?
int i = 0;
for(i=0; i<sz-1; i++)
{
int j = 0;
for(j=0; j<sz-i-1; j++)
{
if(arr[j] > arr[j+1])
{
int tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
}
int main()
{
int arr[] = {3,1,7,5,8,9,0,2,4,6};
bubble_sort(arr);//是否可以正常排序?
for(i=0; i<sizeof(arr)/sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
return 0;
}
方法1,出现问题。调式我们发现,bubble_sort函数内部的sz是1。就是没有成功计算出数组大小,导致函数不能完成排序。
难道数组作为函数参数的时候,不是把整个数组传递过去?
6.2 数组名是什么?
让我们取数组名的地址看一下。
int arr[10] = { 1,2,3,4,5 };
printf("%p\n", arr);
printf("%p\n", &arr[0]);
printf("%d\n", *arr);
看下输出结果,我们可以发现,数组名和数组首元素地址是一样的。数组名就是数组首元素地址
但是若数组名是首元素地址,那么我们计算一下数组名。
int arr[10] = { 1,2,3,4,5 };
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr[0]));
为什么输出的结果是:40和4?不是说两个的地址是一样的吗?
因为 数组名是数组首元素的地址。 有 两个例外 :
- sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组。
- 取地址符号&。&数组名的组合,取出的是数组的地址。&数组名,数组名表示整个数组。
除了这两种情况之外,所有的数组名都表示数组首元素的地址。
6.3 冒泡排序函数的正确设计
之前我们简单的把数组名作为函数参数传递过去,实际上只是把数组首元素地址传递过去而已。
所以之后我们在sizeof()计算数组大小
int sz = sizeof(arr) / sizeof(arr[0])
只是把传递过来的数组(实际上是数组首元素地址),除于数组首元素地址。
自己除于自己,结果sz等于1.
//冒泡排序
//bubble_sort方法
void bubble_sort(int arr[], int sz) {
int i = 0;
for (i = 0; i < sz - 1; i++) {
int j = 0;
for (j = 0; j < sz - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
//main方法
int i = 0;
int arr[] = { 3,1,7,5,8,9,0,2,4,6 };
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
for (i = 0; i < sz; i++) {
printf("%d\n", arr[i]);
}