C数组

数组是能用索引访问的同质元素连续集合。这里所说的连续是指数组的元素在内存中是相邻的,中间不存在空隙,而同质是指元素都是同一类型的。数组声明用的是方括号集合,可以拥有多个维度。

二维数组很常见,我们一般用来表述数组元素的位置。三维或更多维的数组不是很常见,不过有些应用程序会用到。不要混淆二维数组和指针的数组,它们很类似,但是行为有点差别,我们会在指针数组中讲到。

C99标准引入了变长数组,在此之前,支持变长数组的技术是用realloc函数实现的。我们会在用realloc调整数组长度中说明realloc函数。

注意 数组的长度是固定的,当我们声明数组时,需要决定该数组有多大。如果指定过多元素就会浪费空间,而指定过少元素就会限制能够处理的元素数量。realloc函数和变长数组提供了应对长度需要变化的数组的技术。只要略施小计,我们就能调整数组长度,只占用合适的内存。

一维数组

一维数组是线性结构,用一个索引访问成员。下面的代码声明了一个5个元素的整数数组:

int vector[5];

数组索引从0开始,到声明的长度减1结束。vector数组的索引从0开始,到4结束。不过,C并没有强制规定边界,用无效的索引访问数组会造成不可预期的行为。图4-1说明了数组的内存如何分配,每个元素4字节长,且没有初始化。就像指针的长度和类型中所解释的,取决于不同的内存模型,数组的长度可能会不同。

enter image description here

图4-1:数组的内存分配

数组的内部表示不包含其元素数量的信息,数组名字只是引用了一块内存。对数组做sizeof操作会得到为该数组分配的字节数,要知道元素的数量,只需将数组长度除以元素长度,如下所示,打印结果是5:

printf("%d\n", sizeof(vector)/sizeof(int));

可以用一个块语句初始化一维数组,下面的代码把数组中的元素初始化为从1开始的整数:

int vector[5] = {1, 2, 3, 4, 5};

二维数组

二维数组使用行和列来标识数组元素,这类数组需要映射为内存中的一维地址空间。在C中这是通过行列顺序实现的。先将数组的第一行放进内存,接着是第二行、第三行,直到最后一行。

下面声明了一个2行3列的二维数组,用块语句对数组进行了初始化。图4-2说明了这个数组的内存分配,左图说明内存如何映射,右图显示数组在概念上的样子。

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

enter image description here

图4-2:二维数组

我们可以将二维数组当做数组的数组,也就是说,如果只用一个下标访问数组,得到的是对应行的指针。下面的代码说明了这个概念,它会打印每一行的地址和长度:

for (int i = 0; i < 2; i++) {
    printf("&matrix[%d]: %p sizeof(matrix[%d]): %d\n",
            i, &matrix[i], i, sizeof(matrix[i]));
}

下面的输出假设数组位于地址100,因为每行有3个元素,每个元素4字节长,所以组数长度是12:

&matrix[0]: 100 sizeof(matrix[0]): 12
&matrix[1]: 112 sizeof(matrix[1]): 12

指针和多维数组中我们会深入研究这种行为。

多维数组

多维数组具有两个及两个以上维度。对于多维数组,需要多组括号来定义数组的类型和长度。下面的例子中,我们定义了一个具有3行、2列、4阶的三维数组。通常用来标识第三维元素。

int arr3d[3][2][4] = {
    {{1, 2, 3, 4}, {5, 6, 7, 8}},
    {{9, 10, 11, 12}, {13, 14, 15, 16}},
    {{17, 18, 19, 20}, {21, 22, 23, 24}}
};

元素按照行列阶的顺序连续分配,如图4-3所示。

图4-3:三维数组

我们会在后面的例子中用到这些声明。

赞(2)

评论 抢沙发

评论前必须登录!

 

C指针