本篇就来深入的学习一下数组,在初识C语言中只是对数组进行了一个基础的介绍,关于其中的一些细节都没有论述,在学完本篇之后就可以尝试着写一些小游戏:例如 扫雷 , 三子棋 ...,话不多说,正片开始~
1.一维数组的创建和初始化
1.1数组的创建
数组是一组相同类型元素的集合。
数组的创方式:
type_tarr_name [const_n]; //type_t 是指数组的元素类型//const_n 是一个常量表达式,用来指定数组的大小
数组创建的实例:
//代码1intarr1[10]; //代码2intcount=10; intarr2[count];//数组可以正常创建?//代码3chararr3[10]; floatarr4[1]; doublearr5[20];
注:数组创建,在C99标准之前, [ ] 中要给一个常量才可以,不能使用变量。在C99标准支持了变长数组的概念,数组的大小可以使用变量指定,但是数组不能初始化。
可以看到在VS2019上面是不支持变长数组的
1.2数组的初始化
数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值(初始化)
intarr1[10] = { 1,2,3 }; intarr2[] = { 1,2,3,4 }; intarr3[5] = { 1,2,3,4,5 }; chararr4[3] = { 'a',98, 'c' }; chararr5[] = { 'a','b','c' }; chararr6[] ="abcdef";
数组在创建的时候如果想不指定数组的确定的大小就得初始化。数组的元素个数根据初始化的内容来确定
1.3一维数组的使用
对于数组的使用我们之前介绍了一个操作符: [] ,下标引用操作符。它其实就数组访问的操作符。
代码演示:
intmain() { //数组的不完全初始化intarr[10] = { 0 }; //对数组进行初始化//通过下标来进行访问inti=0; for (i=0; i<10; i++) { arr[i] =i; } //打印数组for (i=0; i<10; i++) { printf("%d ", arr[i]); } printf("\n"); //计算数组的元素个数intsz=sizeof(arr) /sizeof(arr[0]); printf("sz = %d\n", sz); return0; }
数组的下标是从0开始的 数组的大小、数组的元素个数、数组内一个元素的大小都是可以通过计算得到的
//数组的大小inta=sizeof(arr); //数组中一个元素的大小intc=sizeof(arr[0]); //数组的元素个数intb=sizeof(arr) /sizeof(arr[0]);
1.4一维数组在内存中的存储
数据是存储在内存中的,一维数组也是存储在内存中的,那一维数组的存储方式又是怎样的呢?可以通过代码来观察一下
intmain() { intarr[5] = { 1,2,3,4,5 }; inti=0; intsz=sizeof(arr) /sizeof(arr[0]); for (i=0; i<sz; i++) { printf("&arr[%d] = %p \n", i, &arr[i]); //通过地址看内存 } return0; }
2.二维数组的创建和初始化
2.1二维数组的创建
数组的创建方式
//数组创建//类型+数组名[行][列];intarr[3][4]; chararr[3][5]; doublearr[2][4];
2.2数组的初始化
//数组初始化intarr[3][4] = {1,2,3,4}; intarr[3][4] = {{1,2},{4,5}}; intarr[][4] = {{2,3},{4,5}};//二维数组如果有初始化,行可以省略,列不能省略
2.3二维数组的使用
二维数组也是通过下标来进行访问的 行和列的小标都是从0开始的
intmain() { //数组初始化intarr[3][4] = { 0 }; inti=0; intj=0; intnum=0; //数组的初始化for (i=0; i<3; i++) { for (j=0; j<4; j++) { arr[i][j] =num; num++; } } //数组的打印for (i=0; i<3; i++) { for (j=0; j<4; j++) { printf("%-2d ", arr[i][j]); } printf("\n"); } return0; }
%2d右对齐 %-2d左对齐
2.4二维数组在内存中的存储
像观察一维数组那样来观察二维数组也是可以的,通过地址来观察内存
intmain() { //数组初始化intarr[3][4] = { 0 }; inti=0; intj=0; intnum=0; //数组的初始化for (i=0; i<3; i++) { for (j=0; j<4; j++) { arr[i][j] =num; num++; } } //数组的打印for (i=0; i<3; i++) { for (j=0; j<4; j++) { printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]); } } return0; }
总结: 二维数组在内存中也是连续存在的 可以使用下标对数组进行访问 二维数组的小标的行和列都是从0开始的
3.数组越界
数组的下标是有范围限制的。 数组的下规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。 所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。 C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序是正确的。
//数组的越界intmain() { intarr[] = { 1,2,3,4,5,6,7,8,9,10 }; inti=0; for (i=0; i<=10; i++) { printf("%d ", arr[i]); //数组下标为10时就会越界访问 } printf("\n"); return0; }
越界访问会造成访问到其他的元素,因此在写代码时要进行越界访问 不仅是一维数组会有越界访问的风险,二维数组也是有越界访问的风险的
4.数组作为函数参数
通常在写代码时,我们会使用函数传参,有时会传一个数组名,比如:实现 冒泡排序 对一个整形数组从低到高排序
要实现这样的代码,首先得知道冒泡排序是什么,冒泡排序的核心思想是通过比较相邻元素的大小,将较大的元素交换到右边,从而使序列中的最大元素逐渐“浮”到最右端,最小元素“沉”到最左端。
例:
排序前: int arr[10] = { 8,5,6,2,3,1,4,9,7,10 }; 排序后: int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
4.1代码实现
如何使用代码来实现冒泡排序呢? 首先得确定排序的趟数,和一趟排序的次数 可以先来分析一下:
因此冒泡排序的趟数设置就是整个数组总长-1,因此循环变量的限制条件就为数组总长-1
关于冒泡排序一趟中排序的次数,需要再设置一个循环变量,但是这个循环变量的限制条件决定了一趟中排序的次数,根据上面的演示,第一趟排序的次数是9,第二次是8,第三次为7.....以此类推,每进行一趟排序,一趟中排序的次数就减一,因此在控制排序次数的循环变量的限制条件为总长减1再减趟数
4.1.1错误演示
代码演示:
voidbubble_sort(intarr[]) { intsz=sizeof(arr) /sizeof(arr[0]);//这样对吗?inti=0; for (i=0; i<sz-1; i++) { intj=0; for (j=0; j<sz-i-1; j++) { if (arr[j] >arr[j+1]) { inttmp=arr[j]; arr[j] =arr[j+1]; arr[j+1] =tmp; } } } } intmain() { intarr[] = { 3,1,7,5,8,9,0,2,4,6 }; inti=0; bubble_sort(arr);//是否可以正常排序?for (i=0; i<sizeof(arr) /sizeof(arr[0]); i++) { printf("%d ", arr[i]); } return0; }
可以看到数组并没有变化,那这是为什么呢?难道我们传参时传递的数组名不是整个数组吗?
4.1.2数组名是什么
intmain() { intarr[10] = {1,2,3,4,5}; printf("%p\n", arr); printf("%p\n", &arr[0]); printf("%d\n", *arr); //输出结果return0; }
结论:
数组名就是数组首元素的地址(有两个例外)
1. sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组。 2. &数组名,取出的是数组的地址。&数组名,数组名表示整个数组。
除了上面的这两个例外,所有的数组名都表示数组首元素的地址
因此上面的错误演示在冒泡排序函数内部求元素个数这种方法是不可行的
4.1.3正确演示
代码演示:
voidbubble_sort(intarr[], intsz) { //设置冒泡排序的趟数inti=0; for (i=0; i<sz-1; i++) { //一趟冒泡排序的次数intj=0; for (j=0; j<sz-1-i; j++) { if (arr[j] >arr[j+1]) //如果前面的一个数字大于后面的数字就交换 { inttmp=arr[j]; arr[j] =arr[j+1]; arr[j+1] =tmp; } } } } voidprint_arr(intarr[], intsz) { inti=0; for (i=0; i<sz; i++) { printf("%d ", arr[i]); } printf("\n"); } intmain() { intarr[] = { 5,4,8,9,7,6,3,2,1,10 }; //使用冒泡排序的算法,来排序intsz=sizeof(arr) /sizeof(arr[0]); printf("排序前:>"); print_arr(arr, sz); bubble_sort(arr, sz); //打印printf("排序后:>"); print_arr(arr, sz); return0; }
5.数组实例
学到这里就可以写一些小游戏的代码了
5.1三子棋
可以点击 三子棋 跳转到关于三子棋博客
5.2扫雷
可以点击 扫雷 跳转到关于扫雷的博客