数组#

数组是一个连续存储同种类型对象的复合类型。这种复合类型将许多值组成一个列表, 在存储同类型的值的时候特别有用。

数组声明与数组类型#

数组声明声明了一个数组。数组的类型由以下属性确定:

  • 元素类型
  • 数组大小(长度)
  • 下面就是一个典型的数组声明:
int my_ints[16];

在多数编译器的要求中,数组的大小是整数常量表达式。也就是说, 数组的大小在声明的时候就会确定,且不可更改

数组本身不能被赋值。但是它的元素可能可以。

整数常量表达式#

整数常量表达式可以有以下方式构成:

  • 整数字面量、字符字面量、立即转型为整数的浮点字面量(如:(int)1.0f
  • 整数常量表达式以赋值、自增、自减、函数调用或逗号以外的运算符构成的表达式。
  • 以及其他

下标运算符#

下标运算符

数组名[表达式]

数组名是一个数组名1

下标运算符提供了访问数组内元素的方法。下标运算符的返回值是左值。也就是说, 你可以对下标运算符的结果赋值。这代表在某个元素的位置写入一个值。如:

my_array[0] = 1;

在C语言中,对于一个数组而言,下标的合法范围是从0开始,到这个数组长度-1为止。

Undefined-behavior

超出数组范围的下标访问是未定义行为。这种行为又被叫做越界访问

尽管C语言的语法不禁止越界访问,也不会检查是否进行了越界访问(因为C语言的数组不会存储长度)。 但是越界访问会造成程序访问了它不应该访问的位置

下面的例子为一个数组每个元素都赋值为其下标值:

int my_ints[16];
for (int i = 0; i < 16; i++)
{
    my_ints[i] = i;
}

下面的例子将一个数组复制到另一个:

int source[16];
int dest[16];
for (int i = 0; i < 16; i++)
{
    dest[i] = source[i];
}

下面的例子:

int A[16];
for (int i = 1; i < 16; i++)
{
    A[i] = A[i - 1] + A[i];
}

改变了A数组。我们一步一步看这个循环的过程。 我们记赋值后的数组为\(A'\),赋值后的

\[ A'[1]=A[0]+A[1]=\sum_{t=0}^1 A[t], \]

而 $$ A'[2]=A[2]+A'[1]=\sum_{t=0}^2 A[t], $$

\[ A'[i]=A[i]+A'[i - 1]=\sum_{t=0}^i A[t]. \]

如此迭代下去,我们发现A[i]被赋值为原来A[0]A[i]的和。你可以试试以下的例子验证这点:

#include <stdio.h>

int main(void)
{
    int A[16];
    for (int i = 0; i < 16; i++)
    {
        A[i] = i * i;
    }
    for (int i = 1; i < 16; i++)
    {
        A[i] = A[i - 1] + A[i];
    }
    for (int i = 0; i < 16; i++)
    {
        printf("%d ", A[i]);
    }
    return 0;
}

打印的应该是一系列的平方和:

0 1 5 14 30 55 91 140 204 285 385 506 650 819 1015 1240

列表初始化#

从上面的例子我们可以看到,对整个数组进行赋值需要一个循环,不是考一个赋值运算符就能解决的。 但是在刚刚声明的时候,我们可以将整个数组所有/部分元素不需要循环一起初始化。 这就是列表初始化。例如以下的例子:

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

在列表初始化中,也可以跳过开头,直接指派下标对应元素的值:

int my_ints[4] = { [2] = 3 };

这两种初始化项合适可以混合使用。如果在指派下标项过后又有一般的初始化项, 那么这个一般初始化项所对应的下标是从指定下标+1开始的。如:

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

数组的值是0, 0, 3, 4, 0。 在数组的初始化中,对于数值类型元素,在没有被指定初始值的时候,其值会被初始化为0。 如下面的初始化不指定任何值:

int my_ints[4] = {};

如果只是单纯的声明而不初始化数组,当数组为全局变量时,其所有值都会被初始化为0, 而对于局部变量,其值不确定

多维数组#

多维数组类型就是用一位数组的类型进行嵌套。 如下面的例子:

int matrix[4][4];

声明了一个4*4的矩阵(二维数组)。


  1. 准确地来说,这里应当是指针表达式,由数组向指针的隐式转换,所以这里能够如此表达。