5.二维数组的使用
操作符 [ ] :下标引用操作符,它其实就是数组访问的操作符,使用两个[ ],访问行和列
二维数组的行和列都是从0开始的
二维数组的使用实例:
//二维数组的使用 #include <stdio.h> int main() { int arr[4][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7},{4,5,6,7}, }; // 行 列 //循环打印二维数组: //printf("%d\n", arr[2][3]); int i = 0; //行号 for ( i = 0; i < 4; i++) { int j = 0; //列号 for ( j = 0; j < 5; j++) { printf("%d ", arr[i][j]); } printf("\n"); //打印完一行后换行 } return 0; }
6.二维数组在内存中的存储(32位操作系统)
(演示代码:)
//二维数组在内存中的存储(32位操作系统) #include <stdio.h> int main() { int arr[4][5] = { 0 }; // 行 列 //循环打印二维数组: //printf("%d\n", arr[2][3]); int i = 0; //行号 for (i = 0; i < 4; i++) { int j = 0; //列号 for (j = 0; j < 5; j++) { printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]); } } return 0; }
(int类型的数组中,相邻的两个元素相差4个字节,因为一个整形元素占4个字节)
(二维数组在内存中也是连续存放的,所以当知道了数组的起始地址,就可以知道后面的其它元素)
(行可以省略,列不能省略的原因:列决定了一行有几个元素,一行有几个元素知道了,下一行放在哪才确定了)
(把“第一行”理解成一个一维数组,“第二行”理解成一个一维数组……所以可以把二维数组看作是一维数组的数组,一个一维数组就是一个元素)
7.数组越界
- 数组的下标是有范围限制的。
数组的下标规定是从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 }; //下标: 0 1 2 3 4 5 6 7 8 9 int i = 0; for ( i = 0; i <= 10; i++) { printf("%d\n", arr[i]); //当i等于10的时候,越界访问了 } return 0; }
8.数组作为函数参数
往往我们在写代码的时候,会将数组作为参数传给函数
例子:冒泡排序函数(算法思想)
(未使用自定义函数:)
//输入10个整数,对这组整数进行排序:(未使用自定义函数) //排序有很多种方法: //1. 冒泡排序 //2. 选择排序 //3. 插入排序 //4. 快速排序 //...... #include <stdio.h> int main() { int arr[10] = { 0 }; int sz = sizeof(arr) / sizeof(arr[0]); //求元素个数 //输入数组 int i = 0; for (i = 0; i < sz; i++) { scanf("%d", &arr[i]); } //排序:冒泡排序,升序 //趟数:总共要排多少次 for (i = 0; i < sz - 1; i++) //sz - 1:10个元素的话只用排9次 { //每趟排几次 int j = 0; for (j = 0; j < sz - 1 - i; j++) //sz - 1 - i:第一次排9次,第二次只用排8次…… { if (arr[j] > arr[j + 1]) //前一个数大于后一个数,进行交换 { //交换,交换两个值时,要有个中间变量 int tmp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tmp; } } } //打印数组 for (i = 0; i < sz; i++) { printf("%d ", arr[i]); } return 0; }
补充:对数组名的理解(重点)
//数组名的理解 #include <stdio.h> int main() { int arr[10] = { 1,2,3,4,5,6 }; //数组名通常情况下就是数组首元素的地址 printf("%p\n", arr); printf("%p\n", &arr[0]); //数组首元素地址 //有2个例外: //1. sizeof(数组名),数组名单独放在sizeof()内部, //这里的数组名表示整个数组,计算的是整个数组的大小 printf("%d\n", sizeof(arr)); //打印结果:40 //按道理,如果 arr 是首元素地址,那打印结果应该是 4 或 8 //2. &数组名,这里的数组名也表示整个数组,取出的是整个数组的地址 printf("%d\n", &arr); //数组的地址也是从起始位置开始的 printf("%d\n", &arr + 1); // &arr + 1:会跳过整个数组,这里是40 // 而 &arr[0] + 1 或 arr + 1 只会跳过1个元素,即4个字节 return 0; }
(未使用自定义函数:注意数组名传参的本质)
//输入10个整数,对这组整数进行排序:(未使用自定义函数) //排序有很多种方法: //1. 冒泡排序 //2. 选择排序 //3. 插入排序 //4. 快速排序 //...... #include <stdio.h> //使用自定义函数 //void bubble_sort(int arr[10]) //虽然写成int arr[10],但这里arr的本质是指针,是个指针变量 void bubble_sort(int* arr, int sz) { //直接把数组元素个数sz传进来 //sizeof(arr):所以这里算的是指针变量的大小即4,不是想要的整个数组大小 //所以 sz = 4 / 4 =1 //int sz = sizeof(arr) / sizeof(arr[0]); //sz=1 int i = 0; for (i = 0; i < sz - 1; i++) //sz - 1:10个元素的话只用排9次 { //每趟排几次 int j = 0; for (j = 0; j < sz - 1 - i; j++) //sz - 1 - i:第一次排9次,第二次只用排8次…… { if (arr[j] > arr[j + 1]) //前一个数大于后一个数,进行交换 { //交换,交换两个值时,要有个中间变量 int tmp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tmp; } } } } int main() { int arr[10] = { 0 }; int sz = sizeof(arr) / sizeof(arr[0]); //求元素个数 //输入数组 int i = 0; for (i = 0; i < sz; i++) { scanf("%d", &arr[i]); } //排序:冒泡排序,升序 bubble_sort(arr, sz); //让这个函数来完成数组arr中数据的排序 //整形数组传参只写地址名就可以了 //arr作为数组进行了传参,传递的是地址 //数组传参,传递的是地址,传递的是首元素的地址 //打印数组 for (i = 0; i < sz; i++) { printf("%d ", arr[i]); } return 0; }
(优化:发现有序之后就不一一排序了,在一趟冒泡排序发现两两排序后都没有对调时,说明已经可以停止排序了)
//输入10个整数,对这组整数进行排序:(未使用自定义函数) //排序有很多种方法: //1. 冒泡排序 //2. 选择排序 //3. 插入排序 //4. 快速排序 //...... #include <stdio.h> //使用自定义函数 //void bubble_sort(int arr[10]) //虽然写成int arr[10],但这里arr的本质是指针,是个指针变量 void bubble_sort(int* arr, int sz) { //直接把数组元素个数sz传进来 //sizeof(arr):所以这里算的是指针变量的大小即4,不是想要的整个数组大小 //所以 sz = 4 / 4 =1 //int sz = sizeof(arr) / sizeof(arr[0]); //sz=1 int i = 0; for (i = 0; i < sz - 1; i++) //sz - 1:10个元素的话只用排9次 { //每趟排几次 int j = 0; // 每一趟开始前就假设已经有序了 int flag = 1; for (j = 0; j < sz - 1 - i; j++) //sz - 1 - i:第一次排9次,第二次只用排8次…… { if (arr[j] > arr[j + 1]) //前一个数大于后一个数,进行交换 { //交换,交换两个值时,要有个中间变量 int tmp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tmp; flag = 0; // 交换了就说明还是无序的 } } //如果没有进入for循环进行交换,说明是有序的,就break停止循环 if (flag == 1) { break; } //这样就不用数组有序了还进行排序 } } int main() { int arr[10] = { 0 }; int sz = sizeof(arr) / sizeof(arr[0]); //求元素个数 //输入数组 int i = 0; for (i = 0; i < sz; i++) { scanf("%d", &arr[i]); } //排序:冒泡排序,升序 bubble_sort(arr, sz); //让这个函数来完成数组arr中数据的排序 //整形数组传参只写地址名就可以了 //arr作为数组进行了传参,传递的是地址 //数组传参,传递的是地址,传递的是首元素的地址 //打印数组 for (i = 0; i < sz; i++) { printf("%d ", arr[i]); } return 0; }