C编程
数组与字符串
在 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