“数组下标应该从0开始还是1开始?我提出的折中方案0.5被拒绝了,而且我想,没有得到应有的认真考虑。”

——斯坦·凯利-布特尔(Stan Kelly-Bootle),计算机科学家

幸运的是,C语言有数组。我的意思是,我知道它被认为是一种低级语言,但它至少内置了数组的概念。由于很多语言的设计都从C语言的语法中获得灵感,你也许已经熟悉用方括号 [] 来声明和使用数组了。

但是C语言几乎只是“表面上”有数组!正如我们稍后会发现,数组实际上只是语法糖——它们本质上都是指针和底层的东西。别慌!但目前,我们就先把它们当作数组来用吧。呼。

6.1 Easy Example

我们来举个例子:

#include <stdio.h>

int main(void)
{
    int i;
    float f[4];  // 声明一个包含4个浮点数的数组

    f[0] = 3.14159;  // 下标从0开始,当然啦
    f[1] = 1.41421;
    f[2] = 1.61803;
    f[3] = 2.71828;

    // 打印所有元素:
    for (i = 0; i < 4; i++) {
        printf("%f\\n", f[i]);
    }
}

声明数组时,必须指定它的大小,并且这个大小必须是固定的。

在上面的例子里,我们创建了一个包含4个浮点数的数组。声明时方括号中的数字就是数组的大小。

后续代码中,我们通过方括号访问数组里的值,可以给它们赋值,也可以读取它们。

希望这对你来说看起来很熟悉,因为你可能已经接触过类似的语言了!

6.2 Getting the Length of an Array

你不能完全做到这一点。C语言不会记录这个信息。你必须在另一个变量中单独管理它。

当我说“不能”时,我实际上是指有些情况下你是可以的。有一种技巧可以在数组声明的作用域内得到数组元素的数量。但一般来说,这在你把数组传递给函数时不起作用。

我们来看一下这个技巧。基本思路是先用 sizeof 取数组的总大小,然后除以每个元素的大小,就能得到数组的长度。例如,如果一个 int 是4字节,数组总长度是32字节,那么数组中必然有 32 ÷ 4 = 8 个 int

int x[12];   // 12个int

printf("%zu\\n", sizeof x);        // 48字节总大小
printf("%zu\\n", sizeof(int));     // 每个int 4字节

printf("%zu\\n", sizeof x / sizeof(int));   // 48/4 = 12个int!

如果是字符数组,那么 sizeof 数组的值就是元素个数,因为 sizeof(char) 被定义为1。对于其他类型,你需要除以每个元素的大小。

但这个技巧只在数组被定义的作用域内有效。如果你把数组传递给函数,它就不起作用。即使你在函数参数中写成“很大”的形式:

void foo(int x[12])
{
    printf("%zu\\n", sizeof x);        // 8?48去哪了?
    printf("%zu\\n", sizeof(int));      // 每个int 4字节

    printf("%zu\\n", sizeof x / sizeof(int));   // 8/4 = 2个int??错了。
}

这是因为,当你“传递”数组给函数时,实际上传递的只是指向第一个元素的指针,而 sizeof 测量的就是这个指针的大小。关于这个内容,可以参考下面“将一维数组传递给函数”一节。