数组与字符串

在 C 语言中,数组用于将相关的数据存储在一个单独的变量名下,并使用索引(也称为下标)进行访问。可以将数组简单地理解为相同类型变量的有序集合或列表。因此,数组通常帮助程序员高效且直观地组织数据集。

稍后我们将讨论指针这一 C 语言的基本概念,指针扩展了数组的特性(数组可以看作是一个常量指针)。目前,我们将仅讨论数组的声明和使用。

数组

C 语言中的数组按以下形式声明:

type name[number of elements];

例如,如果我们需要一个包含六个整数的数组,可以这样写:

int numbers[6];

对于一个名为 letters 的六字符数组,可以这样声明:

char letters[6];

以此类推。

你还可以在声明时初始化数组。只需将初始元素用逗号分隔并放入大括号中,如下所示:

type name[number of elements] = {comma-separated values};

例如,如果我们想初始化一个包含六个整数的数组,初始值为 0, 0, 1, 0, 0, 0:

int point[6] = {0, 0, 1, 0, 0, 0};

当数组像上面这样初始化时,数组的维度可以省略,编译器会自动根据初始数据的大小来确定数组的大小:

int point[] = {0, 0, 1, 0, 0, 0};

这种方式非常有用,因为可以通过简单地添加或删除初始元素来控制数组的大小,而无需调整数组的维度。

如果指定了数组的维度,但没有初始化数组的所有元素,未初始化的元素将默认为 0。这在处理非常大的数组时非常有用。

int numbers[2000] = {245};

上述例子将数组的第一个值设置为 245,其他值设置为 0。

如果我们想访问存储在数组中的变量,例如使用上面的声明,以下代码将把值 1 存储到变量 x 中:

int x;
x = point[2];

C 语言中的数组索引从 0 开始,而不是从 1 开始。上述数组的第一个元素是 point[0],数组中最后一个元素的索引是数组大小减去 1。在上面的例子中,下标从 0 到 5。C 语言不对数组访问进行边界检查。编译器可能不会报错(虽然最好的编译器会报错):

char y;
int z = 9;
char point[6] = { 1, 2, 3, 4, 5, 6 };
// 以下是访问数组边界之外的示例。编译错误不一定会发生
y = point[15];
y = point[-4];
y = point[z];

在程序执行时,越界访问数组并不总是导致运行时错误。程序可能在从 point[-1] 获取值后继续执行。为了避免索引问题,在编写处理数组的循环时,通常会使用 sizeof() 表达式。

许多人使用宏,通过 sizeof() 来计算数组中的元素个数,这些宏通常命名为 lengthof()MY_ARRAY_SIZE()NUM_ELEM()SIZEOF_STATIC_ARRAY() 等。

int ix;
short anArray[] = { 3, 6, 9, 12, 15 };
 
for (ix = 0; ix < (sizeof(anArray) / sizeof(short)); ++ix) {
  DoSomethingWith("%d", anArray[ix]);
}

在上面的例子中,数组的大小没有明确指定。编译器根据初始化列表中的五个值自动确定数组的大小。如果向列表中添加一个值,数组的大小将变为六,且由于 sizeof 表达式在 for 循环中使用,代码会自动适应这一变化。良好的编程实践是声明一个变量来存储数组的元素个数。

size = sizeof(anArray) / sizeof(short);

C 语言还支持多维数组(或者说,数组的数组)。最简单的类型是二维数组。它创建了一个矩形数组——每一行有相同数量的列。如果我们想创建一个包含 3 行 5 列的字符数组,可以这样写:

char two_d[3][5];

要访问或修改这个数组中的值,我们需要两个下标:

char ch;
ch = two_d[2][4];

或者

two_d[0][0] = 'x';

类似地,一个多维数组也可以像这样初始化:

int two_d[2][3] = {{ 5, 2, 1 },
                   { 6, 7, 8 }};

列数必须明确指定;然而,编译器会根据初始化列表自动确定行数。

还有一些奇怪的表示方式:

int a[100];
int i = 0;
if (a[i] == i[a])
{
  printf("Hello world!\n");
}

a[i]i[a] 引用的是相同的位置。(这一点将在下一章解释。)

字符串

在 C 语言中没有内建的字符串处理功能,因此,字符串被定义为字符数组。C 语言允许将字符数组表示为一个字符字符串,而不是字符的列表,并自动在末尾添加空字符作为终止符。例如,要存储字符串 "Merkkijono",我们可以写:

char string[11] = "Merkkijono";

或者

char string[11] = {'M', 'e', 'r', 'k', 'k', 'i', 'j', 'o', 'n', 'o', '\0'};

在第一个例子中,编译器会自动将空字符追加到字符串的末尾;按照惯例,库函数期望字符串以空字符结尾。第二种声明方式显示了个别元素,因此需要手动添加空字符作为终止符。

字符串不一定必须与显式的变量关联。如你已经看到的,字符字符串可以直接创建并作为无名字符串直接使用(例如,使用 printf 函数时)。

要创建一个特别长的字符串,你必须将字符串分成多个部分,通过在第一部分结束时加上引号,并在下一行重新开始字符串(同样以引号开始和结束):

char string[58] = "This is a very, very long "
                "string that requires two lines.";

虽然字符串也可以通过在行末添加反斜杠字符来跨越多行,但这种方式已经不推荐使用。

有一个非常有用的字符串处理库,你可以通过包含另一个头文件来使用:

#include <string.h>  // 新头文件

这个标准字符串库允许对字符串执行各种任务,相关内容将在字符串章节中讨论。

参考文献

  • Pádraig Brady. "C 和 C++ 笔记"。
  • C 编程/指针与数组
  • MINC/参考/MINC1-volumeio-programmers-reference
最后修改: 2025年01月12日 星期日 13:24