数组理论基础
一维数组
数组是计算机科学中最基本的数据结构之一
数组的概念:存放在连续内存空间上的相同类型数据的集合
【eg.】将10个整型数据1-10存放在数组arr中
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
每个数组元素都有下标,下标都是从 0 开始
使用下标来访问数组中的每个元素,eg. arr[0]
对应数组的第一个元素
一维数组的创建和初始化
数组的创建
一维数组的创建方式如下:
type_t arr_name [const_n];
//type_t 是指数组的元素类型
//arr_name 是数组名
//const_n 是一个常量表达式,用于指定数组的大小
下面例举一些数组创建的实例:
//代码1
int arr1[10];//代码2 <🚩错误示例>
int count = 10; //count是变量
int arr2[count]; //[]中需要的是常量表达式//代码3
char arr3[10];
float arr4[1];
double arr5[20];
【注意】数组创建,[]
中要给常量才可以,不能使用变量(如果支持C99,那么可以使用变量,即创建变长数组)
数组的初始化
数组的初始化是指在创建数组的同时给数组元素赋初始值(初始化)
初始化分为完全初始化和不完全初始化,下面举例说明:
-
完全初始化
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
-
不完全初始化
int arr[10] = {1,2,3,4,5};
没有赋值的元素默认为 0
下面例举一些数组初始化的实例:
int arr1[10] = {1,2,3};
int arr2[] = {1,2,3,4,5};
int arr3[5] = {1,2,3,4,5}; //arr2 和 arr3 是一样的效果
char arr4[3] = {'a',98,'c'};
char arr5[] = {'a','b','c'}; //这个数组的长度是3,但是求得的字符串长度是随机值,因为字符串以'\0'为结束标志
char arr6[] = "abc"; //用数组表示字符串,数组元素是:a b c \0 (一共4个元素,注意和 arr5 区分)
char arr7[5] = "abc"; //数组元素是:a b c \0 \0
一维数组的使用
操作符:[]
是下标引用操作符,就是数组访问的操作符
#include <stdio.h>
int main(){int arr[10] = {0}; //数组不完全初始化//计算数组的元素个数int sz = sizeof(arr)/sizeof(arr[0]);//对数组元素赋值(数组是使用下标来访问的,下标从 0 开始)for(int i = 0;i < 10;i++){arr[i] = i;}//输出数组内容for(int i = 0;i < 10;i++){printf("%d ",arr[i]);}return 0;
}
总结:
- 数组是使用下标来访问的,下标是从0开始的
- 数组大小可以通过计算得到
一维数组在内存中的存储
#include <stdio.h>int main() {int arr[10] = {0};int i = 0;for (i = 0; i < 10; i++) {printf("&arr[%d] = %p\n", i, &arr[i]);// %p :按地址的格式打印 —— 十六进制的打印}return 0;
}
总结
- 一维数组在内存中是连续存放的
- 随着数组下标的增长,地址是由低到高变化的
因为数组是连续存储的,所以当我们知道数组的首元素地址时,就可以找到数组中所有的元素
#include <stdio.h>int main() {int arr[10] = {1,2,3,4,5,6,7,8,9,10};int* p = arr; //数组名是数组首元素的地址//让指针 p 指向数组 arr 的第一个元素,也就是 &arr[0]int i = 0;for (i = 0; i < 10; i++) {printf("%d\n", *p); //*p 表示 “取出 p 所指向地址中的值”(解引用)p++; //指针移动到下一个 int 元素}return 0;
}//输出:
1 2 3 4 5 6 7 8 9 10
二维数组
C语言提供了类似矩阵 多维数组
【二维数组可以看作是一维数组,数组中的每个元素也是数组】
二维数组的创建和初始化
二维数组的创建
int arr1[3][4];
char arr2[3][5];
double arr3[2][4];
二维数组的初始化
int arr1[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; //完全初始化
int arr2[3][4] = {1,2,3,4,5,6,7}; //不完全初始化,未赋值部分补0
int arr3[3][4] = { {1,2},{3,4},{5,6} }; //一行一行地初始化
【注意】二维数组初始化时行数可以省略,但是列数不可以省略
int arr4[][4] = { {1,2},{3,4},{5,6} };
二维数组的使用
二维数组的使用也是通过下标的方式
#include <stdio.h>int main() {int arr[3][4] = { {1,2},{3,4},{5,6} };int i = 0;int j = 0;for(i = 0; i < 3; i++){for(j = 0; j < 4; j++){printf("%d ",arr[i][j]);}printf("\n");}return 0;
}//输出:
1 2 0 0
3 4 0 0
5 6 0 0
二维数组在内存中的存储
#include <stdio.h>int main() {int arr[3][4] = { {1,2},{3,4},{5,6} };int i = 0;int j = 0;for(i = 0; i < 3; i++){for(j = 0; j < 4; j++){printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);}}return 0;
}
总结:二维数组在内存中也是连续存放的,每一行内部是连续的,行与行之间也是连续的
数组作为函数参数
在很多时候需要将数组作为函数参数传递,比如:冒泡排序函数将一个整型数组排序
冒泡排序函数的错误设计
//方法1
#include <stdio.h>void bubble_sort(int arr[]){ //形参 arr 本质上是指针,是数组首元素地址//计算数组元素个数,确定冒泡排序趟数int sz = sizeof(arr)/sizeof(arr[0]); //🚩 错误int i = 0;for(i = 0; i < sz-1; i++){//一趟冒泡排序的过程int j = 0;for(j = 0; j < sz-1-i; j++){if(arr[j] > arr[j+1]){//交换int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}
}int main(){int arr[] = {9,8,7,6,5,4,3,2,1}; //需要将数组排序为升序bubble_sort(arr);return 0;
}
修正:
#include <stdio.h>void bubble_sort(int arr[], int sz){int i = 0;for(i = 0; i < sz-1; i++){//一趟冒泡排序的过程int j = 0;for(j = 0; j < sz-1-i; j++){if(arr[j] > arr[j+1]){//交换int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}
}int main(){int arr[] = {9,8,7,6,5,4,3,2,1}; //需要将数组排序为升序int sz = sizeof(arr)/sizeof(arr[0]);bubble_sort(arr,sz);return 0;
}
【注意】数组名是首元素地址
但是有两个例外情况:
sizeof(数组名)
— 数组名表示整个数组 — 计算的是整个数组的大小,单位是字节&数组名
— 数组名表示整个数组 — 取出的是整个数组的地址
#include <stdio.h>int main() {int arr[10] = { 0 };printf("%p\n", &arr);printf("%p\n", &arr+1);printf("%p\n", arr);printf("%p\n", arr+1);return 0;
}