1. 一维数组
数组是一组相同类型元素的集合。
数组的创建方式
type_t arr_name [const_n]; //type_t 是指数组的元素类型 //const_n 是一个常量表达式,用来指定数组的大小
例如:
int arr[4] = {1, 2, 3, 4};
, 创建了一个大小为 4 的整型数组, 创建数组时数组大小可省略, 数组会根据实际情况给一个大小, 既也可以写成int arr[] = {1, 2, 3, 4};
, 还有数组的实际数组元素个数可以小于等于const_n
, 既int arr[100] = {1, 2, 3};
, 余下尚未指定的数据元素值默认为 0; 也可以使用int arr[100] = {0};
, 令数组的数据元素全部为 0.
创建数组语句如下面四种情况:
int arr[4] = {1, 2, 3, 4};
int arr[] = {1, 2, 3, 4};
int arr[100] = {1, 2, 3};
int arr[100] = {0};
const_n
必须是常量值, 不能是变量值, 常量值有四种, 分别是 1) 字面值常量 2) 枚举常量 3) const 修饰的变量 4) #define 定义的标识符常量
如下所示:#define SIZE1 10 enum{ SIZE = 10; } const int SIZE2 = 10; int main(){ int arr[SIZE] = {0};// 枚举常量 int arr1[SIZE1] = {0};// #define 定义的标识符常量 // int arr2[SIZE2] = {0};// const 修饰的变量, 错误, 是 C语言自身的问题, 将文件后缀换为 .cpp 是没有错误的; return 0; }
数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值(初始化)。
int arr1[10] = {1,2,3}; int arr2[] = {1,2,3,4}; int arr3[5] = {1,2,3,4,5}; char arr4[3] = {'a',98, 'c'}; char arr5[] = {'a','b','c'}; char arr6[] = "abcdef";
数组在创建的时候如果想不指定数组的确定的大小就得初始化。数组的元素个数根据初始化的内容来确定.
一维数组的使用
对于数组的使用我们之前介绍了一个操作符:
[]
,下标引用操作符。它其实就数组访问的操作符。#include <stdio.h> int main() { int arr[10] = {0};//数组的不完全初始化 //计算数组的元素个数 int sz = sizeof(arr)/sizeof(arr[0]); //对数组内容赋值,数组是使用下标来访问的,下标从0开始。所以: int i = 0;//做下标 for(i=0; i<10; i++) { //这里写10,好不好? arr[i] = i; } //输出数组的内容 for(i=0; i<10; ++i) { printf("%d ", arr[i]); } return 0; }
总结:
- 数组是使用下标来访问的,下标是从0开始。
- 数组的大小可以通过计算得到。
- 如果数组使用关键字const修饰,数组就只能读不能写
如下所示:
int arr[10]; int sz = sizeof(arr)/sizeof(arr[0]);
一维数组在内存中的存储
#include <stdio.h> int main(){ int arr[10] = {0}; int i = 0; int sz = sizeof(arr)/sizeof(arr[0]); for(i=0; i<sz; ++i) { // %p: 打印指针变量值(打印地址) printf("%p\n", i, &arr[i]); } return 0; }
结果如下图所示:
仔细观察输出的结果,我们知道,随着数组下标的增长,元素的地址,也在有规律的递增。由此可以得出结论:数组在内存中是连续存放的。
2. 二维数组的创建和初始化
二维数组, 也是一维数组, 只不过该一维数组的数据元素又是一个一位数组.
int arr[3][4] = { 1,2,3,4 };
上面这条语句到底是长度为 3 的一维数组, 数组里面的数据元素是长度为 4 的一维数组, 还是说是长度为 4 的一维数组, 数组里面的数据元素是长度为 3 的一维数组?
使用调试器查看数组到底是哪种结构, 如下图所示:
所以该数组是长度为 3 的一维数组, 数组里面的数据元素是长度为 4 的一维数组数组初始化
>int arr[3][4] = {1,2,3,4}; int arr[3][4] = {{1,2},{4,5}}; int arr[][4] = {{2,3},{4,5}};
注意:
- 二维数组如果有初始化,行可以省略,列不能省略
- 多维数组如果有初始化,多维数组中的第一个 [] 里面的数字可以省略, 其他的不能省略
数组的使用
int arr[3][4] = { 1,2,3,4 }; for (int i = 0; i < 3; i++) { for (int j = 0; j < 4; j++) { printf("%p ", &arr[i][j]); } }
数组的存储
上面的代码片段运行结果如下图所示:
通过结果我们可以分析到,其实二维数组在内存中也是连续存储的
3. 数组越界
数组的下标是有范围限制的。数组的下规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的,所以程序员写代码时,最好自己做越界的检查。
4. 数组作为函数参数
冒泡排序
bubblesort(int arr[], int size){ //每次找最小值 //[0,bound)已排序区间 //[bound,size)待排序空间 //初始情况下,所有元素都是待排序,已排序区间是空,待排序区间是整个数组 //每趟找出一个最小值,放在数组开头位置已排序区间就扩充了一个元素 //待排序区间就减少一个元素 //当已排序区间扩充为整个数组,数组就排好序了 int bound = 0; //一共找size次就能够完成整个排序,每次找到一个元素 //已排序区间就扩充一个元素,待排序空间就减少一个元素 for (; bound <= size; bound++) { //具体找最小值并交换 for (int cur = size; cur > bound; cur--) { if (arr[cur - 1] > arr[cur]) { //如果两个相邻元素不满足升序要求,就交换 int temp = arr[cur - 1]; arr[cur - 1] = arr[cur]; arr[cur] = temp; } } } }