目录
数组,就是一组数。数组的概念:一组相同类型元素的集合。
(为什么要创建数组,如果需要1-100的数字的话,总不能创建100个int变量吧。。。)
创建形式:
type-t arr_name [const_n];
- 数组类型
- 自定义标识符,数组名
- 常量,数组大小
创建数组的时候,数组大小必须为常量表达式,也即是说表达式的值必须为常量,如果这里放一个变量进去就会报错。但是! c99语法标准的编译器是有可能编译成功的,因为c99语法引入了变长数组这个概念。
数组初始化:
给数组一些值,就是初始化。
在创建数组的时候再顺便给它赋值便为初始化。
完全初始化:把数组放满就是完全初始化。
不完全初始化:只放一部分。
创建数组的时候如果不确定大小则必须初始化,编译器会根据初始化的内容数量确定数组的大小。
字符数组,可以像整形数组一样用大括号把每一个字符用逗号隔开,赋值给数组,也可以用字符串给数组赋值。
创建字符数组的时候可以直接用双引号的字符串给它赋值,字符串初始化时因为末尾有结束标志\0,所以如果数组不初始化大小,赋值完给的大小总是比字符串多一位。
这两种赋值的方式的区别:
最直接的就是他们的内容和,虽然他们的内容都是“bit”。但是如果初始化数组大小的话,一个大小为3一个为4。在求字符串长度的时候,用字符串赋值的数组能很好的求出长度,因为末尾有\0,但是只放字符进去的字符串因为在数组名开始的内存空间里,求完三个字符之后并不能有效地遇到\0字符串结束标志,所以会求出随机值,打印函数也一样,格式化输出%s因为不会很好的遇到\0,也会在输出”bit”之后继而打印乱码,或许一直到遇到随机的\0才停止。
如果要给一个数组里面全放0,而不是随机值,那么用给它不完全初始化只赋值一个0即可。
只放一个0和放一堆0是不一样的。只放一个0,后面的0都是默认放进去的,而你给它赋值一堆0,这是你主动放进去的。
下拨引用操作符— [ ]
数组是通过下标来访问的,下标是从0开始的。
计算数组的长度可以用数组的大小除以数组其中一个元素的大小。
int 大小 = sizeof ( arr ) / sizeof ( arr [ 0 ] );
一维数组在内存中是连续存放的。
随着数组下标的增长,地址是由低到高变化的。(小的地址叫低地址,大的地址叫高地址)
数组名,是数组首元素的地址!!!
二维数组:
创建:创建一个二维数组和一维数组只有形式上的区别,二位数组有行有列,在定义一维数组的基础上再加一个方括号[ ]即可。
比如:
//在创建一个数组的同时给它赋值,叫做初始化。
二维数组的初始化和一维数组的初始化可以一样,依次给它赋值。
如果整体用一个大括号把赋的值括起来的话,就是一个一个按顺序往后赋值。无论是完全初始化还是不完全初始化都是这样按顺序赋值,不完全初始化情况还是补0。
可以把二维数组的每一行看成一个数组,可以给它每一行赋值:
这样,就给他的每一行分别赋值,每一行没完全初始化后面还是补0
创建二维数组时,行的数量可以省略,但是列不可以。
访问二维数组,也是通过下标的方式来访问,和一维数组一样,它的行号和列号都是从0开始的。
二维数组在内存中的存储形式:
二位数组在内存中也是连续存放的,每一行内部是连续的,跨行也是连续的。每相邻两个元素的间隔都一样大。
就是这样存放的:
这就解释了为什么定义二位数组必须得确定列数,就是得确定每一行放多少个元素,不确定第一行要放多少个元素,那当然也无法确定第二行从哪里开始。
既然二位数组是连续存放的那么只用一个循环即可访问所有元素
可以把二位数组看成多个一维数组,然后就可以找到二维数组中每一个一维数组的数组名。
如下图,arr[1],arr[2],arr[3]就是每一个一维数组名。然后,加上后面的下标,就能访问这个数组里面的元素啦。
数组名是首元素的地址,就是数组第一个元素的地址
但是有例外:
- sizeof(数组名) ,这个时候数组名表示的是整个数组,计算的是整个数组的大小,单位是字节。
- &数组名 ,数组名表示整个数组,取的地址是整个数组的地址。
也就是说只有遇到这两种情况的时候数组名才不是等于首元素的地址。
这边看起来好像说了些什么,又好像什么都没说。因为数组的地址那和数组首元素的地址那不一样吗。也就是 数组名=&数组名 ,完全没有问题啊,的确,在这里他们的地址的数值是一样的,也是同一个地址,但是并不是完全不一样,举个例子:
根据前面学到的可以知道给一个数组地址+1,得到的就是数组的下一个元素的地址。那么,数组名=&数组名的区别就是,给数组地址+1,得到的是这个数组结束后第一个地址,给它+的是整个数组所占的字节数,而给数组名+1,也就是给数组的首元素+1,得到的却是数组的第二个元素的地址。