一维数组
数组是计算机科学中最基本的数据结构之一
数组的概念:存放在连续内存空间上的相同类型数据的集合
【eg.】将10个整型数据1-10存放在数组arr中
c
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
每个数组元素都有下标,下标都是从 0 开始
使用下标来访问数组中的每个元素,eg. arr[0]
对应数组的第一个元素
一维数组的创建和初始化
数组的创建
一维数组的创建方式如下:
c
type_t arr_name [const_n];
//type_t 是指数组的元素类型
//arr_name 是数组名
//const_n 是一个常量表达式,用于指定数组的大小
下面例举一些数组创建的实例:
c
//代码1
int arr1[10];
//代码2 <🚩错误示例>
int count = 10; //count是变量
int arr2[count]; //[]中需要的是常量表达式
//代码3
char arr3[10];
float arr4[1];
double arr5[20];
【注意 】数组创建,[]
中要给常量才可以,不能使用变量(如果支持C99,那么可以使用变量,即创建变长数组)
数组的初始化
数组的初始化是指在创建数组的同时给数组元素赋初始值(初始化)
初始化分为完全初始化 和不完全初始化,下面举例说明:
-
完全初始化
cint arr[10] = {1,2,3,4,5,6,7,8,9,10};
-
不完全初始化
cint arr[10] = {1,2,3,4,5};
没有赋值的元素默认为 0
下面例举一些数组初始化的实例:
c
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
一维数组的使用
操作符:[]
是下标引用操作符,就是数组访问的操作符
c
#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开始的
- 数组大小可以通过计算得到
一维数组在内存中的存储
c
#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;
}

总结
- 一维数组在内存中是连续存放的
- 随着数组下标的增长,地址是由低到高变化的
因为数组是连续存储的,所以当我们知道数组的首元素地址时,就可以找到数组中所有的元素
c
#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语言提供了类似矩阵 多维数组
【二维数组可以看作是一维数组,数组中的每个元素也是数组】
二维数组的创建和初始化
二维数组的创建
c
int arr1[3][4];
char arr2[3][5];
double arr3[2][4];
二维数组的初始化
c
int arr1[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; //完全初始化

c
int arr2[3][4] = {1,2,3,4,5,6,7}; //不完全初始化,未赋值部分补0

c
int arr3[3][4] = { {1,2},{3,4},{5,6} }; //一行一行地初始化

【注意】二维数组初始化时行数可以省略 ,但是列数不可以省略
c
int arr4[][4] = { {1,2},{3,4},{5,6} };
二维数组的使用
二维数组的使用也是通过下标的方式
c
#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
二维数组在内存中的存储
c
#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;
}

总结 :二维数组在内存中也是连续存放的,每一行内部是连续的,行与行之间也是连续的
数组作为函数参数
在很多时候需要将数组作为函数参数传递,比如:冒泡排序函数将一个整型数组排序
冒泡排序函数的错误设计
c
//方法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;
}
修正:
c
#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(数组名)
--- 数组名表示整个数组 --- 计算的是整个数组的大小,单位是字节&数组名
--- 数组名表示整个数组 --- 取出的是整个数组的地址
c
#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;
}
