跳转到内容

C 编程/数组和字符串

来自维基教科书,开放的书籍,开放的世界

C 中的数组用于在单个变量名称下使用索引(也称为下标)存储相关数据。最简单的理解是将数组视为相同类型变量的列表或有序分组。因此,数组通常可以帮助程序员以有效且直观的的方式组织数据集合。

稍后我们将考虑指针的概念,指针是 C 的基础,它扩展了数组的性质(数组可以称为常量指针)。现在,我们只关注它们的声明和使用。

C 数组以以下形式声明

type name[number of elements];

例如,如果我们想要一个包含六个整数(或整数值)的数组,我们在 C 中写

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 };
//examples of accessing outside the array. A compile error is not always raised
y = point[15];
y = point[-4];
y = point[z];

在程序执行期间,越界数组访问并不总是会导致运行时错误。你的程序可能在从 *point[-1]* 中检索值后愉快地继续。为了减轻索引问题,*sizeof()* 表达式通常用于编写处理数组的循环时。

许多人使用一个宏,该宏依次使用 *sizeof()* 来查找数组中的元素数量,这个宏被各种命名为 *“lengthof()”*,[1] *“MY_ARRAY_SIZE()”* 或 *“NUM_ELEM()”*,[2] *“SIZEOF_STATIC_ARRAY()”*,[3] 等等。

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

请注意,在上面的示例中,没有明确指定数组的大小。编译器知道将其大小设置为 5,因为初始化列表中有五个值。向列表中添加一个额外的值会导致它的大小调整为六,并且由于 *sizeof* 表达式在*for*循环中,代码会自动适应此更改。良好的编程实践是声明一个变量 *size*,并将数组中的元素数量存储在其中。

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

C 也支持多维数组(或者更确切地说,是数组的数组)。最简单的类型是二维数组。这将创建一个矩形数组——每一行都具有相同数量的列。为了获得一个包含 3 行和 5 列的字符数组,我们在 C 中写

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]* 指的是同一个位置。(这将在下一章中解释。)

字符串

[编辑 | 编辑源代码]
存储在内存中的字符串“Merkkijono”

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>  //new header file

这个标准字符串库允许对字符串执行各种任务,在字符串一章中进行了讨论。

参考文献

[编辑 | 编辑源代码]


华夏公益教科书