数组
数组
数组是非常有用的工具,通常在需要用一个名称来表示一组相同类型的变量,并通过数值索引访问它们时出现。例如,井字棋棋盘可以存储在一个数组中,每个井字棋棋盘的元素都可以通过其位置轻松访问(左上角可能是位置 0,右下角是位置 8)。本质上,数组是一种在同一个名称下存储多个值的方式。你可以用任何数据类型创建数组,包括结构和类。
一种可视化数组的方式是这样的:
[][][][][][]每一对括号都是一个数组中的槽位,你可以在槽位中存储信息——数组中存储的信息称为数组的元素。这就像你有一组并排排列的变量一样。
让我们看看声明数组的语法。
int examplearray[100]; /* 这声明了一个数组 */这将创建一个具有 100 个槽位的整数数组(数组中存储值的场所)。要访问数组中的特定元素,只需输入数组名称,并在括号中输入一个索引号。这对应于数组中的特定元素。需要注意的是,第一个索引号(也是第一个元素)是 0,最后一个索引号是元素数量减 1。对于 100 个元素的数组,索引号的范围是从 0 到 99。要小心不要通过尝试访问元素 100 而“超出数组的范围”!
例如:
char astring[100];将允许你声明一个包含 100 个元素的 char 数组,或称为存储位置。然后你可以从用户那里接收输入并将其存入该数组,当用户输入一个字符串时,该字符串将存入数组中,字符串的第一个字符位于位置 0,第二个字符位于位置 1,以此类推。以这种方式处理字符串相对容易,因为它允许将任何你能想象到的任意长度的字符串存储在一个变量中,且字符串的每个元素都存储在相邻的位置——想想使用只能存储单个值的简单变量来存储几乎任意长度的字符串将有多么困难。由于我们可以编写递增整数的循环,因此扫描字符串非常容易:
#include <stdio.h>
int main()
{
char astring[10];
int i = 0;
/* Using scanf isn't really the best way to do this; we'll talk about that
in the next tutorial, on strings */
scanf( "%s", astring );
for ( i = 0; i < 10; ++i )
{
if ( astring[i] == 'a' )
{
printf( "You entered an a!\n" );
}
}
getchar();
}让我们来看一些新内容:这里的 scanf 函数调用与之前看到的不同。首先,格式字符串是'%s'而不是'%d';这告诉 scanf 读取一个字符串而不是一个整数。其次,我们不需要使用取地址符!事实证明,当我们把数组传递给函数时,编译器会自动把数组转换成指向数组第一个元素的指针。简而言之,没有括号的数组会像指针一样。所以我们直接把数组传递给 scanf,而不使用取地址符,它完美地工作。
此外,要注意访问数组元素时,我们只需使用括号并输入我们感兴趣的索引;在这种情况下,我们从 0 到 9,检查每个元素是否等于字符'a'。请注意,由于用户可能没有输入一个填满整个数组的字符串,所以其中一些值实际上可能未初始化——我们将在下一个教程中更详细地探讨字符串的处理方式;目前,关键是要理解使用数值索引访问数组的强大功能。想象一下,如果没有数组,你会如何编写这样的代码!哦,天哪。
多维数组是指具有多个索引的数组:它们不仅仅是单行插槽,多维数组可以想象为在两个或更多维度上分布的值。这里有一个简单的方法来可视化二维数组:
[][][][][]
[][][][][]
[][][][][]
[][][][][]
[][][][][]实际声明二维数组的语法几乎与声明一维数组的语法相同,只是你需要为每个维度包含一组括号,并包含维度的尺寸。例如,这里是一个足够大的数组,可以容纳一个标准的跳棋棋盘,有 8 行和 8 列:
int two_dimensional_array[8][8];你可以轻松地使用这个数组来存储某种游戏的信息,或者编写类似井字棋的程序。要访问它,你只需要两个变量,一个用于第一个插槽,一个用于第二个插槽。你可以创建三维、四维,甚至更高维度的数组,但超过三维后,它就变得相当难以想象。
设置数组元素的值和访问元素并执行赋值一样简单。例如,
数组名[数组索引] = 值;例如,
/* 设my_string的第一个元素为字母c */
my_string[0] = 'c';或者,对于二维数组
数组名[数组索引1][数组索引2] = 值;让我再次强调,你永远不应该尝试写入数组的最后一个元素之后的数据,比如当你有一个 10 个元素的数组,而你试图写入[10]元素时。为该数组分配的内存空间只有十个位置(元素 0 到 9),但下一个位置可能是任何内容。写入随机内存可能会导致不可预测的后果——例如,你可能会写入视频缓冲区并改变视频显示,或者你可能写入正在被打开的文档使用的内存并改变其内容。通常,操作系统不会允许这种行为,如果它试图写入未分配的内存,程序将会崩溃。
你会发现数组有很多有用的用途,从用同一个名字存储某些信息,到制作类似井字棋的游戏。我们已经看到了一个使用循环访问数组的例子;这里有一个更有趣的例子!
#include <stdio.h>
int main()
{
int x;
int y;
int array[8][8]; /* 声明一个像棋盘一样的数组 */
for ( x = 0; x < 8; x++ ) {
for ( y = 0; y < 8; y++ )
array[x][y] = x * y; /* 为每个元素设置一个值 */
}
printf( "数组索引:\n" );
for ( x = 0; x < 8;x++ ) {
for ( y = 0; y < 8; y++ )
{
printf( "[%d][%d]=%d", x, y, array[x][y] );
}
printf( "\n" );
}
getchar();
}仅就上述简要提及的最后一个要点:当您想要指向数组时,不需要引用运算符(与)。例如:
char *ptr;
char str[40];
ptr = str; /* 不需要引用操作符(&),将内存地址赋给ptr */相对的
int *ptr;
int num;
ptr = # /* 需要&,将内存地址赋给ptr */数组可以像指针一样行事这一事实可能会导致极大的困惑。
