目录
一维数组
一维数组的创建及初始化
一维数组在内存中的存储
二维数组
二维数组的创建及初始化
二维数组在内存中的存储
数组越界
数组注意事项
1
2
二维数组主要应用:
三子棋
扫雷
一维数组
一维数组的创建及初始化
所谓数组,就是同一种元素的集合。一维数组的表达式为:
数组元素类型 +数组名+ [ 常量表达式];
#include<stdio.h> int main() { //元素类型为 int ,名为arr的共10个元素的数组 int arr[10]; //元素类型为 double ,名为arr1的共10个元素的数组 double arr1[10]; //元素类型为 char ,名为arr2的共10个元素的数组 char arr2[10]; //元素类型为 float ,名为arr3的共10个元素的数组 float arr3[10]; return 0; }
这里注意一点,在C99标准里有变长数组的概念,所谓变长数组并不是指数组会变长,而是指用整型变量或表达式声明或定义的数组。如下所示:
int n=10; int arr[n];
这里要注意的是,变长数组不能初始化,而且在一些编译器里使用变长数组,编译器会报错,比如在vs里就不能使用。
在创建数组的同时,给数组的内容一些合理值,这就是数组初始化。如下:
int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; //当不指定数组大小时,数组大小根据后面内容来确定 int arr1[] = { 1,2,3,4,5 }; //不完全初始化,只初始化数组前三个元素,其余为0; int arr2[10] = { 1,2,3 }; //随机初始化 int arr3[10]; return 0; }
这里我们还要知道,数组是使用下标来访问的,下标是从0开始。
一维数组在内存中的存储
看如下代码:
#include <stdio.h> int main() { int arr[10] = { 0 }; int i = 0; //sizeof用来求数组大小,通常用如下表达式来求数组大小 int sz = sizeof(arr) / sizeof(arr[0]); for (i = 0; i < sz; ++i) { //%p打印地址专用 printf("&arr[%d] = %p\n", i, &arr[i]); } return 0; }
这里我们可以看到,每一个数组后面的地址都会比前面大4,而我们知道,在32位环境下,一个地址就是32个二进制位,存储起来也就是32个比特位空间,即4个字节,也就是说,这些数组元素的地址随着下标的增长,是由低地址向高地址连续存放的!
二维数组
二维数组的创建及初始化
看下图:
#include<stdio.h> int main() { //3行4列,int类型,名为arr的二维数组 int arr[3][4]; //3行4列,char类型,名为arr1的二维数组 char arr1[3][4]; //3行4列,double类型,名为arr2的二维数组 double arr2[3][4]; return 0; }
二维数组与一维数组相比较,多了行与列的区别。同样,我们也可以在创建数组的同时给数组内容赋合理的值,即二维数组初始化,大家看下图:
从这里我们可以看出,在二维数组初始化时,可以省略行,但不能省略列,同时,初始化的内容我们可以用{ }来限定。
同样,二维数组和一维数组一样,也是有下标的,从0行0列开始,如下:
二维数组在内存中的存储
与一维数组一样,我们看如下代码:
#include <stdio.h> int main() { int arr[3][4]; //i控制行 int i = 0; for (i = 0; i < 3; i++) { //j控制列 int j = 0; for (j = 0; j < 4; j++) { //打印arr里每个元素的地址 printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]); } } return 0; }
我们可以看到,在32位机器里,二维数组与一维数组一样,每个数组元素的地址都要比前面那个元素多4字节,由此,我们可以看出,二维数组在内存中的存储依然是由低地址向高地址连续存放,如图所示:
数组越界
我们知道,数组都是通过下标来使用的,而下标又是有范围的,数组的下标从0开始,假如一共有n个元素,则下标最大为n-1。
而数组的下标一旦超过这个最大值,就会造成越界访问,所谓越界访问,就是超出合法空间访问,也就是超过了数组所在空间,就好像这样:
通过一段代码来验证:我们来看一下下面代码运行的结果:
#include<stdio.h> int main() { int arr[4] = { 1,2,3,4 }; printf("%d", arr[4]); return 0; }
我们可以看到,编译器并没有报错,但我们打印出来的值却不在我们可控范围内,这就是数组越界。
同样,二维数组也存在数组越界:
数组注意事项
1
我们要知道,数组名在作为参数时,传送的是数组首元素的地址,并不是整个数组:
#include<stdio.h> int print(int arr[]) { return sizeof(arr) / sizeof(arr[0]); } int main() { int arr[3] = { 1,2,3 }; int tmp = print(arr); printf("%d", tmp); return 0; }
有的人可能会说,打印的结果是3,但其实并非如此:
因为在这里,print(arr),这里的arr实际上是首元素,即arr[0]的地址,传送过去后,sizeof(arr)其实求的就是首元素的大小,即这里的sizeof(arr)就等价于sizeof(arr[0]),所以最终结果为1.
数组名表示首元素地址,但是,有两种情况是例外的,就是size
of(数组名),这里的数组名是表示整个数组。而我们上面的例子里,数组名arr先是作为参数传送的,所以传送过去的就是数组首元素的地址,所以求sizeof(arr)的时候,实际上求得是数组首元素的大小,注意分得清。
另外一种情况就是&数组名,这里表示的是取出整个数组的地址。这里的数组名表示整个数组。
除此之外,其余任何地方的数组名,都是表示数组首元素地址。
2
我们要注意数组中字符串类型的数组,具体看如下例题:
#include <stdio.h> int main() { char str[] = "hello boy"; printf("%d %d\n", sizeof(str), strlen(str)); return 0; }
注意!:我们要知道,字符串结束的标志是\0,在这个数组里,实际上是有个\0的存在的,只不过被隐藏了,大家看下图所示:
而sizeof求的是数组所占内存空间的大小,char类型在
32位机器下,一个字符占用1个字节,这里加上\0一共是10个字符,所以一共是10*1=10个字节。
而strlen是专门用来求字符串长度的,\0不算在内,所以结果应该是9
同样,理清楚后,下面这道题也就很简单了:
acX实际上加上\0,一共8个字符,acY一共7个字符,并不等价
同样,在计算长度时,结束标志是\0,由于acY没有\0,所以长度随机值。
所以,正确答案为C。
二维数组主要应用:
三子棋与扫雷就运用到了二维数组,大家闲来无事可以写一下:
三子棋
扫雷
以上暂且讲到这,诸君加油。