197 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			197 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
|   | --- | |||
|  | title: Arrays | |||
|  | localeTitle: 数组 | |||
|  | --- | |||
|  | # C中的数组
 | |||
|  | 
 | |||
|  | ## 问题
 | |||
|  | 
 | |||
|  | 在尝试解释什么是数组之前,让我们看看我们想要以相反的顺序打印用户给出的10个数字的代码。 | |||
|  | 
 | |||
|  | ```C | |||
|  | #include <stdio.h> 
 | |||
|  |  int main(void) {  | |||
|  |     int a, b, c, d, e, f, g, i, j, k;  | |||
|  |     scanf("%d", &a);  | |||
|  |     scanf("%d", &b);  | |||
|  |     ...  | |||
|  |     printf("%d", k);  | |||
|  |     printf("%d", j);  | |||
|  |     printf("%d", i);  | |||
|  |     ... //and so on..  | |||
|  |   | |||
|  |     return 0;  | |||
|  |  }  | |||
|  | ``` | |||
|  | 
 | |||
|  | 所以,这看起来有点单调乏味。 到目前为止,每个变量都有一些特殊的作用。但是现在,如果我们可以在一个地方存储多个值并且可以访问它们在行中的位置(第一个值,第二个等),那将是很好的。另一种看待这种情况的方法是,假设您要存储一组名称,不需要为每个名称创建不同的变量,而是可以创建一个名称数组,其中每个名称都有其唯一的标识或_索引_ 。另外,我们可以在它们上面使用循环,这些是你稍后会学到的东西,但基本上它们会一遍又一遍地做同样的事情。 例如。从用户读取或打印出值。 | |||
|  | 
 | |||
|  | ## C中的数组
 | |||
|  | 
 | |||
|  | 数组是具有给定大小的容器。它们包含**相同类型的**变量。您可以使用其_索引_访问存储在数组中的变量。 我们来看一些代码: | |||
|  | 
 | |||
|  | ```C | |||
|  | #include <stdio.h> 
 | |||
|  |  int main(void) {  | |||
|  |     int arr[4] = {1, 2, 3, 88};  | |||
|  |     int brr[] = {78, 65};  | |||
|  |     int crr[100] = {3};  | |||
|  |   | |||
|  |     int var = arr[0];  | |||
|  |   | |||
|  |     return 0;  | |||
|  |  }  | |||
|  | ``` | |||
|  | 
 | |||
|  | 现在让我们打破一下语法: | |||
|  | 
 | |||
|  | ```C | |||
|  | int arr[4] = {1, 2, 3, 88};  | |||
|  | ``` | |||
|  | 
 | |||
|  | 在这里,您创建了一个名为`arr`的`ints` (整数) `array` 。该数组有4个要素: `1` , `2` , `3` , `88` 。注意语法! | |||
|  | 
 | |||
|  | ```C | |||
|  | datatype name[number of elements]  | |||
|  | ``` | |||
|  | 
 | |||
|  | 这个数组的第一个元素是`1` ,第二个是`2`等。 | |||
|  | 
 | |||
|  | ```C | |||
|  | int brr[] = {78, 65};  | |||
|  | ``` | |||
|  | 
 | |||
|  | 您不必事先告诉维度。这里将使用大括号之间的元素创建两个数组。 | |||
|  | 
 | |||
|  | ```C | |||
|  | int crr[100] = {3};  | |||
|  | ``` | |||
|  | 
 | |||
|  | 如果你这样做,那么第一个元素将是`3` ,但其余的将是`0` 。 | |||
|  | 
 | |||
|  | ```C | |||
|  | int var = arr[0];  | |||
|  | ``` | |||
|  | 
 | |||
|  | 这里创建一个名为`var`的int,它被初始化为arr的第0个元素。 **非常重要的是要注意** ,在C中,索引从零开始而不是1.这意味着要访问第一个元素,索引(括号之间)为0,访问第二个元素,索引为1等。 在此示例中, `var`将存储值`1` 。 | |||
|  | 
 | |||
|  | ## 概观
 | |||
|  | 
 | |||
|  | *   一维数组就像一个列表;二维数组就像一张桌子;尽管具体实现可能,但C语言对数组中的维数没有限制。 | |||
|  |      | |||
|  | *   有些文本将一维数组称为向量,将二维数组称为矩阵,并在维数未指定或不重要时使用通用术语数组。 | |||
|  |      | |||
|  | 
 | |||
|  | ## C中的多维数组
 | |||
|  | 
 | |||
|  | C还支持多维数组。 | |||
|  | 
 | |||
|  | ```C | |||
|  | datatype name[size1][size2]...[sizeN]  | |||
|  | ``` | |||
|  | 
 | |||
|  | 二维数组很常见,可以使用以下语法进行初始化。可以逻辑地将第一个索引视为行,将第二个索引视为列。此示例有2行5列。 | |||
|  | 
 | |||
|  | ```C | |||
|  | int arr[2][5] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};  | |||
|  | ``` | |||
|  | 
 | |||
|  | 使用上述语法可能难以可视化二维数组,因此开发人员通常使用可选的嵌套括号来阐明数组的结构。这也是初始化二维数组的有效方法。 | |||
|  | 
 | |||
|  | ```C | |||
|  | int arr[2][5] = {  | |||
|  |     {0, 1, 2, 3, 4},  | |||
|  |     {5, 6, 7, 8, 9}  | |||
|  |  };  | |||
|  | ``` | |||
|  | 
 | |||
|  | 两个嵌套的for循环可用于以表格格式打印二维数组的内容。 | |||
|  | 
 | |||
|  | ```C | |||
|  | #include <stdio.h> 
 | |||
|  |   | |||
|  |   | |||
|  |  int main() {  | |||
|  |     const int rows = 2, cols = 5;  | |||
|  |   | |||
|  |     int arr[rows][cols] = {  | |||
|  |             {0, 1, 2, 3, 4},  | |||
|  |             {5, 6, 7, 8, 9}  | |||
|  |     };  | |||
|  |   | |||
|  |     for (int row = 0; row < rows; row++) {  | |||
|  |         for (int col = 0; col < cols; col++) {  | |||
|  |             printf("%5d", arr[row][col]);  | |||
|  |         }  | |||
|  |         puts("");  | |||
|  |     }  | |||
|  |   | |||
|  |     return 0;  | |||
|  |  }  | |||
|  | ``` | |||
|  | 
 | |||
|  | ```C | |||
|  |     0    1    2    3    4  | |||
|  |     5    6    7    8    9  | |||
|  | ``` | |||
|  | 
 | |||
|  | ## 字符串
 | |||
|  | 
 | |||
|  | 为了存储字符串/多个字符,我们在C中使用`char arrays` ,因为该语言没有内置的特殊类型。需要注意的一点是,终止空值会自动添加到结尾,表明它是结束字符串。但是,您也可以使用花括号`{}`初始化字符串,但您必须手动添加终止空值。 | |||
|  | 
 | |||
|  | 像这样: | |||
|  | 
 | |||
|  | ```C | |||
|  | char string[6] = "Hello"; //here you get Hello\0, which is why we need an array with the length of 6  | |||
|  | ``` | |||
|  | 
 | |||
|  | 就像上面示例中的int数组一样,有几种方法可以为char数组赋值: | |||
|  | 
 | |||
|  | ```C | |||
|  | char string[] = "I do not want to count the chars in this.";  | |||
|  |  char string2[] = {'C','h','a','r',' ','b','y',' ','c','h','a','r','\0'};  | |||
|  |  char string3[] = "This is a string"  | |||
|  |                  "with two lines";  | |||
|  | ``` | |||
|  | 
 | |||
|  | 相当于上面的方法,您还可以创建一个指向char数组的指针: | |||
|  | 
 | |||
|  | ```C | |||
|  | char* string = "I do not want to count the chars in this.";  | |||
|  | ``` | |||
|  | 
 | |||
|  | ## 典型的错误,提示
 | |||
|  | 
 | |||
|  | *   当你有一个数组填充了值,并且你想创建一个与第一个数组完全相同的数组时,永远不要这样做: | |||
|  | 
 | |||
|  | ```C | |||
|  | double first[] = {2,3,7};  | |||
|  |  double second[] = first;  | |||
|  |  //Or this:  | |||
|  |  double a[5], b[5]  | |||
|  |  a = b;  | |||
|  | ``` | |||
|  | 
 | |||
|  | 您**只能**逐个处理数组中的值。您**无法一次性分配所有内容** ,当您稍后了解指针时,原因将会很清楚。 | |||
|  | 
 | |||
|  | > (基本上,数组的第一个元素指向一个内存地址,之后的元素是第一个元素旁边的“房子”。所以从技术上讲,数组就是它的第一个元素的内存地址。当你想分配第二个元素时对第一个数组进行数组,由于类型不同而遇到错误,或者您正在尝试更改第二个数组中第一个元素的第二个内存地址。)
 | |||
|  | 
 | |||
|  | *   如果要创建数组,则必须告诉其大小或为其指定值。不要这样做: | |||
|  | 
 | |||
|  | ```C | |||
|  | int arr[];  | |||
|  | ``` | |||
|  | 
 | |||
|  | 计算机必须知道为阵列创建多大的存储空间。稍后,您将了解如何创建稍后定义大小的容器。 (再一次,指针。) | |||
|  | 
 | |||
|  | *   当您从数组中索引时,编译器并不总是会给您一个错误。这称为未定义行为,我们只是不知道会发生什么。它可能导致程序崩溃,只是放慢速度,任何事情。 | |||
|  | 
 | |||
|  | ```C | |||
|  | int test[6];  | |||
|  |  int a = test[-2];  | |||
|  |  int b = test[89];  | |||
|  | ``` | |||
|  | 
 | |||
|  | C不检查索引边界的原因很简单:C是一种有效的语言。它是成功的,所以你的程序是最快的:与硬件等很好地通信。一个编写得很好的C代码不包含索引错误,那么C为什么要在运行时检查呢? | |||
|  | 
 | |||
|  | *   当您尝试访问数组的最后一个元素时。假设数组A的长度为4,并且在访问最后一个元素时为 A \[4\]将返回错误,因为索引从0开始。 |