一.一维数组的创建与初始化
1.1 数组的创建
数组是一组相同类型元素的集合。
数组的创建方式:
type_t(是指数组的元素类型) arr_name [const_n](是一个常量表达式,用来指定数组的大小)
#include<stdio.h> //C99之前数组只能是常量指定大小 //C99之后引用了变长数组概念,数组大小是可以用变量指定的。 int main() { int arr[5]; int arr2[3 + 2]; char arr3[8]; int n = 0; scanf("%d", &n); int arr4[n]; return 0; }
不过vs是不支持用变量来指定大小的。
1.2 数组的初始化
这里面有不完全初始化(剩余元素默认为0) 也有通过ascll码值代替字母 也可以不输入大小,通过内容自动判定。
不过关于字符数组需要注意一点:字符型不会自动放‘\0’,而字符串会。
1.3 一维数组的使用
数组通过下标来访问:
int main() { int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; int sz = sizeof(arr) / sizeof(arr[0]); int i = 0; for (i = 0; i < sz; i++) { printf("%2d ", arr[i]); } printf("\n"); //如果想要倒序,也可以改变 for (i = 0; i < sz; i++) { arr[i] = 10 - i; printf("%2d ", arr[i]); } return 0; }
1.4 一维数组在内存中的存储
我们可以通过地址来说明:
int main() { int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; int sz = sizeof(arr) / sizeof(arr[0]); int i = 0; for (i = 0; i < sz; i++) { printf("&arr[%d]=%p\n", i, &arr[i]); } printf("\n"); //如果想要倒序,也可以改变 /*for (i = 0; i < sz; i++) { arr[i] = 10 - i; printf("%2d ", arr[i]); }*/ return 0; }
可以得出相邻地址之间都相差4个字节(整型元素是4个字节)是连续存放的并随下标增长,地址是低到高的。
二.二维数组的创建与初始化
2.1 二维数组的创建
2.2 二维数组的初始化
//对于二维数组,如果初始化了,对于行数是可以省略的,但是列不能省略 int main() { int arr[3][5] = {0};//不完全初始化 int arr1[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} }; int arr2[][10] = { {1,2},{2,3,4},{5,5,5} }; return 0; }
对于二维数组,如果初始化了,对于行数是可以省略的,但是列不能省略。
2.3 二维数组的使用
假想中的二维数组:
通过下标遍历简单访问二维数组
int main() { int i = 0; int j = 0; int arr[3][5] = { {1,2},{4,5},{6,7,8} }; for (i = 0; i < 3; i++) { for (j = 0; j < 5; j++) { printf("%d ", arr[i][j]); } printf("\n"); } return 0; }
我们还可以改变数组:打印1-15
int main() { int i = 0; int j = 0; int arr[3][5] = { {1,2},{4,5},{6,7,8} }; for (i = 0; i < 3; i++) { for (j = 0; j < 5; j++) { arr[i][j] = i * 5 + j+1; } } for (i = 0; i < 3; i++) { for (j = 0; j < 5; j++) { printf("%d ", arr[i][j]); } printf("\n"); } return 0; }
2.4 二维数组在内存中的储存
打印一下二维数组的地址:
int main() { int arr[3][5] = { {1,2},{4,5},{6,7,8} }; int i = 0; int j = 0; for (i = 0; i < 3; i++) { for (j = 0; j < 5; j++) { printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]); } } return 0; }
我们会发现所有元素之间都差4个字节,这与我们想的行列图并不一样,而应该是这样:
二维数组在内存中也是连续存放的。
二维数组其实是一维数组的数组。
可以把第一行的数组名看作arr[0],后面的[j]就是一维数组的大小。
三.数组越界
四.数组作为函数参数
冒泡排序基本思想:
int main() { int arr[] = { 10,9,8,7,6,5,4,3,2,1 }; int sz = sizeof(arr) / sizeof(arr[0]); int i = 0; int j = 0; //趟数 for (i = 0; i < sz - 1; i++) { for (j = 0; j < sz - 1 - i; j++) { if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } else { break; } } } for (i = 0; i < sz ; i++) { printf("%d ", arr[i]); } return 0; }
10个数趟数是9趟,每一趟需要对比交换的次数都会减少,这里用sz-1-i来表示。
4.1 冒泡排序函数的错误设计
void sort(int arr[]) { int sz = sizeof(arr) / sizeof(arr[0]); int i = 0; int j = 0; //趟数 for (i = 0; i < sz - 1; i++) { for (j = 0; j < sz - 1 - i; j++) { if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } else { break; } } } } int main() { int arr[] = { 10,9,8,7,6,5,4,3,2,1 }; sort(arr); int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } return 0; }
当我们把写好的代码封装到函数时发现出了问题。
没有排序了。
这里就涉及到了数组传参的问题了。
4.2 数组名是什么?
结论:数组名就是数组首元素的地址。
但是有两个意外:1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节。2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
通过地址可以发现,首个地址加1只是移动到下一个位,但&arr加1是直接跨越了整个数组的大小。
4.3 冒泡排序函数的正确设计
void sort(int arr[]) { int sz = sizeof(arr) / sizeof(arr[0]); int i = 0; int j = 0; //趟数 for (i = 0; i < sz - 1; i++) { for (j = 0; j < sz - 1 - i; j++) { if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } else { break; } } } } int main() { int arr[] = { 10,9,8,7,6,5,4,3,2,1 }; sort(arr); int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } return 0; }
sort(arr)不是特殊的两种情况,就是数组的首元素地址,本质上形参用指针接受。所以上述形参中arr[]其实是个指针(当然形参也可以用int *arr),sizeof(arr)(等于4)/sizeof(arr[0])=1,sz=1.
在这种情况下我们可以把sz的求法放在main函数上,因为传的就是地址,接收的就只能是指针,不管怎么算大小都只能是4,所以只能在主函数求出,经过计算再传回去。
void sort(int arr[],int sz) { int i = 0; int j = 0; //趟数 for (i = 0; i < sz - 1; i++) { for (j = 0; j < sz - 1 - i; j++) { if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } else { break; } } } } int main() { int arr[] = { 10,9,8,7,6,5,4,3,2,1 }; int sz = sizeof(arr) / sizeof(arr[0]); sort(arr,sz); int i = 0; for (i = 0; i < sz; i++) { printf("%d ", arr[i]); } return 0; }
小疑惑:
也不用对首个元素地址感到奇怪,为什么不传整个数组呢?其实是因为后续有对数组进行遍历,只要知道首个元素的地址,就可以知道后面的地址了,进而遍历得到整个数组。