零基础学C语言——数组

这是一个C语言系列文章,如果是初学者的话,建议先行阅读之前的文章。笔者也会按照章节顺序发布。

我们讨论过函数,其中涉及到了一些数组和指针,本篇详细说明数组。

数组定义

数组是一种集合结构,与数学种谈到的集合类似,用来存放同类型数据。在C语言中,数组是定长的,即数组有其最大长度限制,超过限制的访问会导致程序崩溃或异常行为。

定义一个数组的一般形式如下:

数据类型 数组名[数组长度];

其中,数据类型不仅包含了之前文章中介绍的几种 ,还包含后续文章将会介绍的自定义类型、结构体类型等,数组长度为整数,数组名的命名规则与 的命名规则一致。

下面看几种数组定义的例子:

int i_array[100]; //定义整型数组,名为i_array,数组长度为100,即可以容纳100个整数char c_array[100]; //定义字符型数组,名为c_array,数组长度为100,即可容纳100个字符 

数组的声明与 和 的声明作用是一样的,是为了告诉编译器,这个数组在本文件或者其他源文件中有定义,避免当前文件编译因找不到定义而报错。

数据类型 数组名[数组长度];

看似与数组定义一样,是的,的确可以写成一样的,但数组长度可以省略:

int i_array[100];和int i_array[];

这里需要注意,如果省写数组长度,那么在使用sizeof计算i_array长度时编译器会报错

数组初始化

在定义变量时,我们可以定义并赋初值,数组亦然,但是数组有几种定义并初始化的写法:

1.定义并给出全部初始值

int a[3] = {1, 2, 3};或int a[] = {1, 2, 3}; 

即初值用{}包裹,且每个元素间用逗号隔开。

对于同时给定初始值的定义,我们是可以省略数组长度的,因为编译器会根据初始值内容判断数组长度。

2.定义并给出部分初始值

int a[3] = {1, 2};

此时数组长度不可省写,否则将被认为数组只有两个元素。数组a的前两个元素分别是1和2,第三个元素数值未知。

3.定义字符数组

字符数组的定义赋初值写法与其他基础类型的定义有所不同

char s[6] = "hello";char s[] = "hello";

上面这两者是等价的,即定义了一个数组长度为6的字符数组。

细心的读者可能会发现,hello只有五个字符,为什么会是6个元素长度呢?

这是因为双引号内的字符串(也是字符数组)都隐含的在最后包含了一个'\\0'字符来表示字符串结束。因此这类字符串的长度都是双引号内字符个数总和加1。如果使用sizeof运算符计算s的长度,返回的数值就是6。

对于字符型数组(不管是char还是unsigned char)有一种特殊的初始化写法——定义并将数组元素值都清零

char s[100] = {0};unsigned char us[100] = {0};

此时,数组长度不可省略,且这里不只是初始化数组的第一个元素,而是将数组全部元素值设置成0。

这样的写法仅限于清零,如果换用别的数值,则会变成部分初始化。

数组元素

其实,数组本质上也是一片连续的内存空间,与我们在变量一篇中停车场例子很像。

零基础学C语言——数组

事实上,数组的每一个元素单元就是一个变量

我们再次以停车位使用为例来看下数组元素是如何被使用的。这里,我们假设举例镜头最近的停车位位置记为0,并向远处依次加一,且假定这一排有10个停车位。

那么这样一排停车位转换到C语言上,可以如下定义:

int parking_area[10];

之所以定义为整型,是因为每一种车型都可以用一个独特的整数来代替其名字,即车名与整数做了一个映射关系。

此时,一辆宝马驶入第1个车位,我们假定宝马对应整数为1000,那么代码可以写成:

parking_area[0] = 1000; //上面提到过第一个车位的位置为0

这里,我们用到了 。

本篇文章中,数组元素的访问都是通过下标来进行的,关于指针访问元素留待后续指针文章中讨论。

数组的下标个数与数组长度相等,且下标数值从0开始依次加1,即上例中的下标为0~9。

这时又来了一辆奔驰(对应整数记为1001),停入了第二个车位,那么代码如下:

parking_area[1] = 1001;

如果,宝马开走了(假设无车停放记为0),那么代码可以写成:

parking_area[0] = 0;

一个可编译运行的例子

#include int main(void){    char a[10] = {0};    int i;    for (i = 0; i < sizeof(a); ++i) {        printf("%d\\n", a[i]);    }    return 0;}

大家可以 一下例子,这里是将定义数组a并将其所有元素全部清0。然后使用数组下标配合循环语句完成数组元素的遍历访问。关于循环的内容,将在后续文章中给出。

多维数组

上面讨论的内容涉及到的例子都是一维数组——即每个数组元素都是一个数值而非数组

下面,我们就来介绍复杂一些数组形式,我们以二维数组为例进行演示。

int a[2][3];

这里我们就定义了一个二维数组a,它类似一个2行3列的表格或者矩阵。

对于这个二维数组,定义同时初始化可以使用如下方式:

int a[2][3] = {{1, 2, 3}, {4, 5, 6}};或int a[][3] = {{1, 2, 3}, {4, 5, 6}};

可以看到,其最外层数组包含了两个元素,这两个元素又分别是两个相同长度的一维数组。

同时,在定义同时初始化的情况下,第一维的数组长度可以省略,编译器将以初值中的元素个数自动填充。

int a[2][3];或int a[][3];

即可以省写一维数组长度部分。

对于

二维数组的元素访问,可以用如下形式:

a[0][1] = 10; //第1行第2列元素赋值10a[1][2] = 99; //第2行第3列元素赋值99

对于更高维度的数组,在日常生产环境下是不多见的,其一般形式如下:

数据类型 数组名[m][n]...;或数据类型 数组名[m][n]... = {{{...},...},...};

特征就是:

  1. 是几维数组,数组名后的方括号就有几个
  2. 是几维数组,初值中就要嵌套几层{}数组
  3. 是几维数组,访问其元素时数组下标运算符([])就要有几个
  4. 对于二维及其以上维度的数组,在定义同时初始化时,只有第一维度的数组长度可以省略
  5. 对于二维及其以上维度的数组,声明时只有第一维度的数组长度可以省略


喜欢的读者可以关注码哥,也可以在下方留言评论,如果有不清楚的地方也可以私信码哥,我会第一时间回复。


分享到:


相關文章: