目录
1. 一维数组
1.1 数组的概念
数组是一组相同类型元素的集合。(1)数组中存放的是 1 个或者多个元素,数组元素个数不能为 0。(2)数组中存放的数据的类型是相同的。
1.2 一维数组的创建
一维数组创建的基本语法:
type arr_name[常量值];
type:数组中元素的数据类型(char,int,struct 等)。
arr_name:数组名。
常量值:表示数组的大小。
int math[20]; // 创建 math 数组用于存储 20 人的数学成绩,数据成绩的类型为 int
double score[10]; // 创建 score 数组用于存储 10 个人得分情况,得分的类型为 double
1.3 一维数组的初始化
数组在创建的时候,给定一些初始值,就叫做数组的初始化。 数组的初始化一般使用大括号,将数据放在大括号中。初始化的时候给定元素个数不能超过数组的大小。
#include <stdio.h>
int main()
{
int arr1[5] = {1, 2, 3, 4, 5}; // 完全初始化
int arr2[6] = { 1, 5 }; // 不完全初始化:前面元素为给定的值,剩余的元素默认初始化为 0。
int arr3[7]; // 定义数组的时候可以不初始化,但是默认为随机值。
return 0;
}
1.4 数组的类型
数组也是有类型的,数组算是一种自定义类型,去掉数组名留下的就是数组的类型。
int arr1[10];
int arr2[12];
char ch[5];
arr1 数组的类型是 int [10],arr2 数组的类型是 int [12],ch 数组的类型是 char [5]。
1.5 数组下标
C 语言规定数组是有下标的,下标从 0 开始,假设数组有 n 个元素,最后一个元素的下标是 n - 1 ,下标就相当于数组元素的编号,如下:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
C 语言数组的访问提供了一个操作符 " [] ",这个操作符叫做下标访问操作符。
有下标访问操作符,就可以轻松访问数组的元素了。访问下标为 7 的元素,就使用 arr[7],如下:
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", arr[7]);
printf("%d\n", arr[3]);
return 0;
}
1.5.1 数组元素的遍历
可以通过 for 循环 + 下标的方式对整个数组的元素进行遍历。
#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;
}
1.5.2 数组的输入
想对数组中的元素进行修改,可以使用 scanf 进行输入对数组的元素进行修改。
#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;
}
注:scanf 访问数组中单独的一个元素的时候需要加上取地址运算符。
1.6 一维数组在内存中的存储
我们可以通过打印数组每个元素的地址来观察数组在内存中是如何存储的。
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
for (int i = 0; i < 10; i++)
{
printf("&arr[%d] = %p\n", i, &arr[i]);
}
return 0;
}
从输出的结果上可以看出来,数组随着下标的增长,地址是由小变大的,并且每两个响铃的元素之间相差 4,这是因为这个数组中目前存储的数据类型为 int 类型,int 类型每一个元素需要 4 个字节进行存储。
所以可以得出结论:数组在内存中是连续存放的。
1.7 sizeof 计算数组元素个数
如果想直到数组的元素个数,可以使用 sizeof 关键字来计算类型或者变量的大小,sizeof 返回的并不是数组的元素个数,返回的是数组占据多少字节,可以通过占据的字节数除以数组中数据类型的方式来计算数组中的元素个数。
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
printf("数组占用的字节数: %d\n", sizeof(arr));
printf("数组中一个元素的大小: %d\n", sizeof(arr[0]));//计算⼀个元素的⼤⼩,单位是字节
int sz = sizeof(arr) / sizeof(arr[0]);
printf("数组中元素的个数: %d\n", sz);
return 0;
}
2. 二维数组
2.1 二维数组的创建
把一维数组作为数组的元素时,这时候该数组就是二维数组。同理将二维数组作为数组的元素时,这时候该数组就是三位数组。二维数组以上的数组统称为多维数组。
创建二维数组的语法如下:
type arr_name[常量值1][常量值2];
type:表示二维数组中数据的类型。
arr_name:表示二维数组的数组名。
常量1:表示二维数组的行数。
常量2:表示二维数组的列数。
int arr[3][5];
double data[2][8];
上述中 arr 表示为一个 3 行 5 列的二维数组,存储的数据类型为 int 类型;data 表示为一个 2 行 8 列的二维数组,存储的数据类型为 double 类型。
2.2 二维数组的初始化
2.2.1 不完全初始化
#include <stdio.h>
int main()
{
int arr1[3][5] = { 1, 2, 3, 4, 5, 6, 7};
int arr2[3][5] = { 0 };
return 0;
}
如上,可以看出,当对二维数组进行初始化的时候,是一行一行进行初始化的,等该行初始化完,在继续初始化下一行,并且剩余没有初始化的元素默认初始化为 0。
2.2.2 完全初始化
#include <stdio.h>
int main()
{
int arr3[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
return 0;
}
2.2.3 按行初始化
#include <stdio.h>
int main()
{
int arr4[3][5] = { {1,2},{3,4},{5,6} };
return 0;
}
2.2.4 初始化时省略行,但是不能省略列
int arr5[][5] = { 1,2,3 };
int arr6[][5] = { 1,2,3,4,5,6,7 };
int arr7[][5] = { {1,2}, {3,4}, {5,6} };
2.3 二维数组的下标
二维数组是有行有列的,只要锁定行和列就能锁定数组中唯一的一个元素。
C语⾔规定,⼆维数组的⾏是从0开始的,列也是从0开始的,如下所示:
int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
如果想要访问 7 这个数组,那么就可以通过 arr[2][4] 进行访问。
#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;
}
2.3.1 二维数组的遍历
一维数组是使用 for 循环 + 数组下标的方式进行遍历的,那么二维数组也可以通过同样的方式对数组进行遍历,只是遍历二维数组的时候需要两层 for 循环。下列就通过遍历的方式向二维数组中输入数据并通过 printf 打印出来。
#include <stdio.h>
int main()
{
int arr[3][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7 };
int i = 0;//遍历⾏
//输⼊
for (i = 0; i < 3; i++) //产⽣⾏号
{
int j = 0;
for (j = 0; j < 5; j++) //产⽣列号
{
scanf("%d", &arr[i][j]); //输⼊数据
}
}
printf("\n");
//输出
for (i = 0; i < 3; i++) //产⽣⾏号
{
int j = 0;
for (j = 0; j < 5; j++) //产⽣列号
{
printf("%d ", arr[i][j]); //输出数据
}
printf("\n");
}
return 0;
}
2.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 个字节,跨行位置处的两个元素也是相邻的,也只相差 4 个字节,所以二维数组中的每个元素都是连续存放的。
3. C99 中的变长数组
在 C99 标准之前,C 语言在创建数组的时候,数组大小的指定只能使用常量、常量表达式。这样的语法限制在创建数组的时候不够灵活,有时候数组创建大了会造成空间浪费,有时候数组创建小了又不够用。
C99 中给出一个变长数组(variable-length array,VLA)的新特性,允许我们可以使用变量指定数组大小。
int n = a+b;
int arr[n];
上面示例中,arr 数组就是变长数组,因为它的长度取决于变量 n 的值,编译器在编译的时候无法确定 n 的值为多少,只有运行时才能知道 n 是多少。
变长数组的根本特征就是数组长度只有运行时才能确定,所以变长数组不能初始化。好处是在开发时不用随意为数组指定一个估计的长度,可以在运行时为数组分配精确的长度。变⻓数组的意思是数组的大小是可以使⽤变量来指定的,在程序运⾏的时候,根据变量的⼤⼩来指定数组的元素个数,⽽不是说数组的⼤⼩是可变的。数组的大小⼀旦确定就不能再变化了。
在 VS2022 上虽然支持大部分 C99 语法,但是没有支持 C99 变长数组,下面是在 gcc 编译器上测试的结果:
#include <stdio.h>
int main()
{
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]);
}
printf("\n");
return 0;
};