1. 概念数组是一组相同类型元素的集合。
从这个概念中我们就可以发现2个有价值的信息:
数组中存放的是1个或者多个数据,但是数组元素个数不能为0。数组中存放的多个数据,类型是相同的。数组分为一维数组和多维数组,多维数组一般比较多见的是二维数组。
2. 一维数组的创建与初始化创建基本语法如下:
代码语言:javascript复制type arr_name[常量值];存放在数组的值被称为数组的元素,数组在创建的时候可以指定数组的大小和数组的元素类型。
type 指定的是数组中存放数据的类型,可以是:char、short、int、float 等,也可以是自定义的类型。
arr_name 指的是数组名的名字,这个名字根据实际情况,起的有意义就行。
[]中的常量值是用来指定数组的大小的,这个数组的大小是根据实际的需求指定就行。
比方说,创建一个 int 类型的数组存放一个20个人的班级的数学成绩
代码语言:javascript复制int math[20];初始化在数组创建的时候给它一些初始值就叫做数组的初始化,初始化有两种类型:
完全初始化不完全初始化代码语言:javascript复制//完全初始化
int arr[5] = {1,2,3,4,5};
//不完全初始化
int arr2[6] = {1};//第⼀个元素初始化为1,剩余的元素默认初始化为0
//错误的初始化 - 初始化项太多
int arr3[3] = {1, 2, 3, 4};数组的类型我们知道 int 表示整形变量类型,float表示浮点数,那数组有没有类型呢?
事实上,数组也是有类型的,数组算是一种自定义类型,去掉数组名留下的就是数组的类型。如:
代码语言:javascript复制int arr1[10];
int arr2[12];
char ch[5];它们的类型分别是
代码语言:javascript复制int arr1
int arr2
char ch3. 一维数组的使用了解了一维数组的基本语法,一维数组可以存放数据,存放数据的目的是对数据的操作这些知识之后,我们应该如何使用一维数组呢?
一维数组的下标C语言规定数组是有下标的,下标是从0开始的,假设数组有n个元素,最后一个元素的下标是n-1,下标就相当于数组元素的编号,如下:
"[]"是下标引用操作符,是c语言提供的根据数组下标访问元素的操作符。
如:
代码语言:javascript复制#include
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;
}输出结果很显然,是
代码语言:javascript复制8
4数组元素的访问那么,如何打印这一整个数组呢?
很简单,数组下标可以访问数组元素,那么只要产生所有的数组下标不就可以访问所有的元素了吗,利用循环结构,我们可以实现这一点:
代码语言:javascript复制#include
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;
}输出结果
在能够访问所有的数组元素之后,想必你也知道该如何输入每个数组元素了吧,这里给出一个例子:
代码语言:javascript复制#include
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;
}代码结果4. ⼀维数组在内存中的存储要想深入地了解数组,了解数组在内存中的存储显然是十分有必要的。
我们可以通过
代码语言:javascript复制printf("%p",&arr[i]);来得到一个数组元素的地址,那么通过数组元素的访问,我们可以得到数组中每个元素的地址
比如:
代码语言:javascript复制#include
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;
}(小提示:将编译方式改为x86可以减少地址位数)
可以看到,在这个数组中,每个元素的地址差了4,而这又刚好是 int 类型的大小,这也就意味着,数组中的元素在内存中是顺序存储的。
数组在内存中的存储5. 利用 sizeof 计算数组元素个数遍历数组的时候,我们需要使用数组中元素的个数,在上面我们是直接使用预定好的数组元素个数,但是这样会导致后期修改的时候比较麻烦,或者有时候会不知道数组的大小,那么C语言中有办法使用程序计算数组元素个数
吗?
sizeof 是C语言的一个可以计算类型或者变量大小关键字,其实 sizeof 也可以计算数组的大小。
可以用下面的方式计算数组的元素:
代码语言:javascript复制#include
int main()
{
int arr[10] = { 0 };
int sz = sizeof(arr) / sizeof(arr[0]);
printf("%d\n", sz);
return 0;
}输出结果为:10
6. 二维数组概念前面学习的数组被称为一维数组,数组的元素都是内置类型的,如果我们把一维数组做为数组的元素,这时候就是二维数组,二维数组作为数组元素的数组被称为三维数组,二维数组以上的数组统称为多维数组。
二维数组的概念创建可以通过与创建一维数组相似的固定格式创建一个二维数组:
代码语言:javascript复制type arr_name[常量值1][常量值2];例如:
代码语言:javascript复制int arr[3][5];
double data[2][8];解释:上述代码中出现的信息
3表示数组有3行
5表示每一行有5个元素
int 表示数组的每个元素是整型类型
arr 是数组名,可以根据自己的需要指定名字
data数组意思基本一致,只是数组元素类型为浮点数。
初始化不完全初始化代码语言:javascript复制int arr1[3][5] = {1,2};
int arr2[3][5] = {0};这样就完成了二维数组的不完全初始化。
arr1的第0行的第0,1个元素分别被初始化为1 2,没有被初始化的位置全部被初始化为0。
arr2的所有元素都被初始化为 0。
二维数组的不完全初始化完全初始化代码语言:javascript复制int arr3[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};(当然,这里的空格只是辅助理解的,并没有实际意义,也不会影响程序的运行。)
二维数组的完全初始化按照行初始化既然二维数组有行的概念,那么是否有办法只初始化每一行中的个别元素呢?
当然是有的
代码语言:javascript复制int arr4[3][5] = {{1,2},{3,4},{5,6}};这样,数组的0,1,2行的第0,1个元素就被初始化了,而其他没被初始化的部分同样被初始化为0。
按照行初始化初始化时可以省略行,但是不能省略列代码语言:javascript复制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}};如果你省略行,程序可以根据初始化时的元素个数和每行的元素个数找到最小的行数,并作为这个数组的实际行数。但如果省略列,程序就不知道应该如何初始化了。
二维数组的元素访问与一维数组一样,二维数组也可以通过数组下标来访问二维数组的每一个元素,进而使用二维数组进行输入输出。
C语言中,二维数组的行和列都是从 0 开始的。
比如这样一个数组:
代码语言:javascript复制int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};它的行列就是这样的:
我们可以通过循环的嵌套来输出或输入二维数组。
比如我们要输入并输出上面的这个 arr数组。
代码语言:javascript复制#include
int main()
{
int arr[3][5] = { 0 };
//输⼊
for (int i = 0; i < 3; i++) //产⽣⾏号
{
for (int j = 0; j < 5; j++) //产⽣列号
{
scanf("%d", &arr[i][j]); //输⼊数据
}
}
//输出
for (int i = 0; i < 3; i++) //产⽣⾏号
{
for (int j = 0; j < 5; j++) //产⽣列号
{
printf("%d ", arr[i][j]); //输出数据
}
printf("\n");
}
return 0;
}二维数组的输入输出二维数组在内存中的存储可以通过
代码语言:javascript复制printf("%p ",&arr[i][j]);来打印二位数组元素的地址。
二维数组在内存中的存储
从输出的结果来看,每一行内部的每个元素都是相邻的,地址之间相差4个字节,跨行位置处的两个元素(如:arr[0][4]和arr[1][0])之间也是差4个字节,所以二维数组中的每个元素都是连续存放的)。
二维数组在内存中的存储(2)7. C99标准引入变长数组在C99标准之前,C语言在创建数组的时候,数组大小的指定只能使用常量、常量表达式,或者如果我们初始化数据的话,可以省略数组大小。
代码语言:javascript复制int arr1[10];
int arr2[3+5];
int arr3[] = {1,2,3};很显然由于这样的语法限制,我们在创建数组时十分不灵活,为了确保数组的空间足够使用,我们往往会创建较大的数组,这样会造成空间的浪费。
C99中给一个变长数组(variable-length array,简称VLA)的新特性,允许我们可以使用变量指定数组大小。
代码语言:javascript复制int n = a+b;
int arr[n];数组 arr 就是变长数组,它的长度取决于变量n 的值,编译器没法事先确定,只有运行时才能知道 n是多少。
变长数组的根本特征,就是数组长度只有运行时才能确定,所以变长数组不能初始化。它的好处是程序员不必在开发时,随意为数组指定一个估计的长度,程序可以在运行时为数组分配精确的长度。
有个值得注意的点,变长数组的意思是数组的大小是可以使用变量来指定的,在程序运行的时候,根据变量的大小来指定数组的元素个数,而不是说数组的大小是可变的。数组的大小一旦确定就不能再变化了。
当然,要注意,即使是一些比较主流的 IDE 也是不支持C99标准的,也就无法使用变长数组,比如VS2022。
下面通过搭载 gcc 编译器的 devc++ 进行演示。
代码语言:javascript复制#include
int main()
{
int a = 0;
scanf("%d",&a);
int arr[a];//创建变长数组
int i=0;//值得注意的是,devc++中,循环变量不能在 for 循环的初始化语句中创建
for(i=0;i
{ scanf("%d",&arr[i]); }