目录
2.3二维数组的使用
1.一维数组的创建和初始化
1.1数组的创建
数组一组相同类型元素的集合
数组的创建方式
type_t arr_name [ const_n ];
//type_t 是指数组的元素类型
//const_n 是一个常量表达式,用来指定数组的大小
数组创建的实例:
C99标准之前,数组的大小必须是常量或者常量表达式
C99之后,数组的大小可以是变量,可以支持变长数组
#include<stdio.h> int main() { int n=0; scanf("%d",&n); int arr[n]; }
此时这个数组就是变长数组,要注意变长数组是不能初始化的
上面这段代码只能在支持C99标准的编译器上编译
像gcc的编译器就是支持变长数组的
1.2数组的初始化
数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值(初始化)
数组在创建的时候如果想不指定数组的大小就得初始化,数组的元素个数根据初始化的内容来确定
1.3一维数组的使用
[ ]下标引用操作符,是数组访问的操作符
编号是从0开始的,这里的编号就是数组的下标
arr[4]找到的是下标为4的元素
总结:
1.数组是使用下标来访问的,下标是从0开始
2.数组的大小可以通过计算得到
1.4一维数组在内存中的存储
每个元素之间都相差4,因为这个数组是整型类型,每个元素都占4个字节
数组在内存中都是连续存放的
2.二维数组的创建和初始化
2.1二维数组的创建
//数组创建
int arr [ 3 ] [ 4 ] ;//相当于三行四列
char arr [ 3 ] [ 5 ] ;
double arr [ 2 ] [ 4 ] ;
2.2二维数组的初始化
//数组初始化
int arr [ 3 ] [ 4 ] = { 1 , 2 , 3 , 4 };
int arr [ 3 ] [ 4 ] = { { 1 , 2 } , { 4 , 5 } } ;//按照需求分组,不完全初始化
int arr[ ] [ 4 ] = { { 2 , 3 } , { 4 , 5 } } ;//二维数组如果初始化,行可以省略,列不能省略
//这里编译器会自动会认为第一个[ ]为2
2.3二维数组的使用
二维数组的使用也是通过下标来使用的
行标和列标都是从0开始
给每个元素赋值,并且打印在屏幕上
如何将二维数组看作一维数组?(将每一行看作一个元素)
将第一行元素看作一维数组中的一个元素
将第二行元素看作一维数组中的第二元素
所以上面这个数组可以看作有三个元素的一维数组
可以把二维数组理解为:一维数组的数组
可以将arr[0],arr[1],arr[2]理解为数组名
2.4二维数组在内存的存储
我们返现每个相邻的元素之间都相差了四个字节,由此我们可以得出结论
二维数组在内存中是连续存放的
我们画成表格的形式只是为了便于理解
3.数组越界
数组的下标是有范围限制的
数组的下标是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1
所以数组的下标如果小于0,或者大于n-1,就是数组越界访问,超出了数组合法空间的访问
C语言本身是不做数组下标越界检查,数组越界了,编译器不一定会报错,但是编译器不报错,并意味着程序就是正确的,所以这就需要我们自己检查数组是否越界访问
比如
int arr[10]={0};
这里就不存在数组下标是10的元素,如果要访问下标为10的元素就是数组越界访问,这里编译器可能不会报错,打印出随机值
二维数组存在列越界和行越界
4.数组作为函数参数
将数组作为参数传给函数,比如实现一个冒泡排序函数(升序)
冒泡排序的核心思想是:两个相邻元素进行比较
一趟冒泡排序让一个数据来到它最终应该出现的位置上,像这组数据中,十个元素进行九趟排序,最后一个元素不用比较,最后一趟排序比较晚,它就在它本来应该在的位置,所以n个元素,进行n-1趟比较
4.1冒泡排序函数的错误设计
这里我们发现,并没有得到我们想要的结果,为什么呢?
这里是我们需要直到数组名是什么?
4.2数组名是什么
数组名本质上是:数组首元素的地址,地址应该使用指针来接收
在冒泡排序函数中,这里arr看似是数组,本质上是指针变量,在86位机器上是所有的指针变量的大小都是4个字节,所以在冒泡排序函数中sizeof(arr)是4,sizeof(arr[0])也是4,sz在这里的计算结果是1
数组名确实能表示首元素的地址
但是又两个例外:
- sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节
- &数组名,这里的数组名表示整个数组,取出的是整个数组的地址
除了这两个例外,数组名表示的都是首元素地址
注意这里打印出的地址都是十六进制的最后一个打印的地址相差0x28,转换成十进制正好是40个字节
二维数组的数组名的理解
4.3冒泡排序函数的正确设计