目录
前言:
学习编程,有些知识画图比较容易理解,我们也要学会画图分析,这样更能加深我们的理解。下面我就用图和代码注释的方式来讲解数组这部分的内容,当然还有一些柔性数组,指针数组,函数指针数组这些稍有点难度的指数我会放在进阶讲。接下来的几篇文章会跟你们讲解数组的练习实例,例如三子棋,扫雷。
话不多说,先来一张美图,直接开始。
一,一维数组
1.1 什么是数组(array)?
数组是一组相同类型元素的集合(注意:相同类型)
格式如下:
type_t arr_name [const]
//type_t 是指数组的元素类型
//arr_name 是指数组的名字
//const 是来指定数组的大小,一般是常量表达式,但在c99中某些编译器可以用变量指定,但数组不能初始化
如:我们创建一个包含5个元素的int型数组,数组的元素有1,2,3,4,5.
我们再创建一个包含5个元素的char型数组,数组的元素有a,b,c,d,e.
int arr1[5] = {1, 2, 3, 4, 5};
char arr2[5] = {'a','b','c','d','e'};
1.2 数组初始化及使用
初始化是指,在创建数组的同时给数组的内容一些合理的初始值。代码如下:
int arr1[3] = {1, 2, 3};
int arr2[10] = {1, 2, 3, 4};
char arr3[] = {'a','b','c'};
char arr4[] = {"abc"};
char arr5[10] = {"abc"};
我们观察上面的代码:arr2里面有4个元素,但创建的时候有10个空间,那么其余6个空间的元素是会什么?arr3 和 arr4 里面的元素数量是相同的吗?
这些问题,我调试了一下,你们看看结果:
从上图得知:
数组 arr2 中没有给初始值的部分都变成了"0"。arr5也是,后面默认为“\0”(“\0”ASCII码值为0)。
数组 arr3 和 arr4 显然不一样,arr4 有 4 位,最后一位是“ \0 ” ,arr4中用双引号括住的“abc”是字符串,在数组中字符串后面默认加上“\0”,arr3里用单引号的是单个字符,后面不会跟“\0 ”。
数组使用如下:
#include <stdio.h>
int main()
{
int arr[10] = {0}; //arr不完全初始化
int sz = sizeof(arr) / sizeof(arr[0]); //用sizeof()计算数组元素个数,这里sz是10;
int i = 0;
for(i = 0; i < sz; i++) //对数组内容赋值,数组下标是从0开始
{
arr[i] = i;
}
for(i = 0; i < sz; i++) //输出数组的内容
{
printf("%d ",arr[i]);
}
return 0;
}
重点:
1,数组是使用下标来访问,下标是从0开始。
2,数组的大小可以通过计算获得。
int arr[10];
int sz = sizeof(arr)/sizeof(arr[0]);//将计算的个数放在sz中
1.3一维数组在内存中的存储
一维数组在内存中的存储是连续存放的吗?让我们观察下面打印数组地址的例子:
观察可知:
随着数组下标的增长,元素的地址,也有规律的递增(每次增加4字节是因为整形占4个字节)
因此可得出结论:数组在内存中是连续存放的。
二,二维数组
2.1 二维数组的创建和初始化
//数组的创建
int arr1[2][3];
char arr2[4][3];
float arr3[3][3];
//数组的初始化
int arr1[2][3] = {{1,2,3},{4,5,6}};
char arr2[4][3] = {{1,2,3},{},{},{4,5,6};
float arr3[3][3] = {0};
我们可以这样理解二维数组:
arr[2][3]: 第一个表示行数,有两行,第二个表示列数,有三列。行数可以没有,但列数必须要有。
例如: int arr[3][ ] = {1,2,3,4,5,6} 是非法的,编译器直接报错,因为编译器确定不了列数。
int arr[ ][3] = {1,2,3,4,5,6} 可以运行,编译器根据列数来推出行数为2。
2.2 二维数组的使用
二维数组的使用也是通过下标的方式。
看下面代码:
#include <stdio.h>
int main()
{
int arr[3][4] = {0}; //初始化为0
int i = 0;
for(i=0; i<3; i++) //每列有3行 输入值
{
int j = 0;
for(j=0; j<4; j++) //每行有4列
{
arr[i][j] = i*4+j;
}
}
for(i=0; i<3; i++) //每列有3行 输出值
{
int j = 0;
for(j=0; j<4; j++) //每行有4列
{
printf("%d ", arr[i][j]);
}
}
return 0;
}
2.3 二维数组的存储
二维数组在内存中的存储也是连续存放的吗?让我们观察下面打印数组地址的例子:
通过结果我们可以分析到,其实二维数组在内存中也是连续储存的。
三,数组越界
注意:
数组的下标是有范围限制的。
数组的下规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。
所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。
C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的,所以我们写代码时,最好自己做越界的检查。
#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int i = 0;
for(i=0; i<=10; i++)
{
printf("%d\n", arr[i]); //当i等于10的时候,越界访问了
}
return 0;
}
二维数组的行和列也可能存在越界。
四,数组名
看下面例子,能更好地理解数组名。
这两个地址居然一模一样。这是不是表示数组名就是数组首元素的地址了呢?
如果数组名是首元素地址,那么:
int arr[10] = {0};
printf("%d\n",sizeof(arr));
为什么输出结果是:40?
下面两点需要我们注意了:
1,sizeof(数组名),计算的是整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组。
2,&数组名,取出的是数组的地址。&数组名,数组名表示整个数组。
3,除去上面两点之外,所有的数组名,表示数组首元素的地址。
好了,到这就结束了,希望对你有帮助,如果有不足之处,请多多指教。