一、数组的概念
数组是一组相同类型元素的集合。
那数组有什么要求呢?
- 数组中至少要有一个数据。
- 数组中的数类型必须相同。
- 数组在内存中是连续存储的。
那用数学的语言来描述就是:数组是在内存中连续存储的具有相同类型的一组数据的集合。
二、一维数组
2.1 一维数组的创建与初始化
2.1.1 数组的创建
一维数组定义方式如下:
type_t arr_name [const_n]; //type_t 是指数组的元素类型 //arr_name 是数组的名字 //const_n 是一个常量表达式,用来指定数组的大小
例如:
//代码1 int arr1[10]; char arr2[10]; float arr3[1]; //代码2 //用宏定义的方式 #define X 3 int arr5[X]; //代码3 //错误使用 int count = 10; int arr6[count];//数组是否可以正常创建?
注:数组创建, [] 中要给一个常量才可以,不能使用变量。可以直接用常量,或者使用宏定义。
2.1.2 数组的初始化
数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值。
1. 数组大小和数值个数相等,这种方式也被称为完全初始化。
例如:
int arr[5] = {1,2,3,4,5};
2. 数组大小大于初始数,这种方式被称为不完全初始化。
例如:
int arr[5] = {1,2,3};
3. 不指定数组大小
int arr[] = {1,2,3,4,5};
注:果进行初始化,可以不在[]声明有几个元素,数组会默认初始化几个元素,数组大小就是几个元素,但是不初始化就一定要声明有几个元素哦~,否则就会报错
4. 字符数组的存储
需要注意的是,给字符数组初始化时如果指定大小,那么指定大小要比字符数多一个,因为在字符串中结束标志是'\0',它也需要占据一个存储位置。如果没有这个结束标志,虽然程序不会报错,但在使用的时候无法得知结束位置,会导致使用错误。
2.2 一维数组的使用
2.2.1 数组下标
c语言数组规定是有下标的,下标是从0开始的(而不是1),假设数组有n个元素,最后⼀个元素的下标是n-1,例如:int arr[10]={1,2,3,4,5,6,7,8,9,10}。
arr | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
2.2.2 数组的打印
我们知道了数组下标的概念,那我们怎么进行访问数组,打印出来呢?
让我们参考如下代码:
int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr[i]);//循环输出 } return 0; }
打印结果为:1 2 3 4 5 6 7 8 9 10
2.2.3 数组的输入
输入和我们正常的差不多,只是吧变量换成了数组。
#include <stdio.h> int main() { int arr[10] = {1,2,3,4,5,6,7,8,9,10}; int i = 0; for(i=0; i<10; i++) { scanf("%d", &arr[i]); } for(i=0; i<10; i++) { printf("%d ", arr[i]); } return 0; }
2.3 一维数组在内存中的存储
既然有元素的存在,那数组中每个元素是如何存储的呢?
让我们参考以下代码:
#include <stdio.h> int main() { int arr[10] = {1,2,3,4,5,6,7,8,9,10}; int i = 0; for(i=0; i<10; i++) { printf("&arr[%d] = %p\n ", i, &arr[i]); } return 0; }
输出结果如下:
仔细观察输出的结果,可知随着数组下标的增长,元素的地址,也在有规律的递增。 由此可以得
出结论:数组在内存中是连续存放的。
2.4 sizeof的用法
在遍历数组的时候,我们经常想知道数组的元素个数,那c语言中要怎么得到呢?可以使⽤sizeof。
sizeof是c语言里面的一个关键字是可以计算类型或者变量⼤⼩的,其实 sizeof 也可以计算数组的大小。
例如:
#include <stido.h> int main() { int arr[10] = {0}; printf("%d\n", sizeof(arr)); return 0; }
这⾥输出的结果是40,计算的是数组所占内存空间的总⼤⼩,单位是字节。
我们又知道数组中所有元素类型都是相同的,那我们只要知道一个元素的大小就能知道数组中有多少个元素。
#include <stido.h> int main() { int arr[10] = {0}; printf("%d\n", sizeof(arr[0]));//计算⼀个元素的⼤⼩,单位是字节 return 0; }
接下来就能计算出数组中元素的个数。
#include <stido.h> int main() { int arr[10] = {0}; int sz = sizeof(arr)/sizeof(arr[0]); printf("%d\n", sz); return 0; }
输出结果是10,代表着数组中有十个元素。
三、二维数组
3.1 二维数组的创建与初始化
3.1.1 数组的创建
- 类型说明符 数组名[ 常量表达式][ 常量表达式];
- 类比一维数组的定义,二维数组第一个常量表达式表示行,第二个常量表达式表示列。
- 二维数组创建时,行数可以忽略不写。并且所有维度的数组其第一个方括号的内容可忽略。
//数组创建 int arr[3][4];//[行数][列数] char arr[][5]; double arr[2][4];
3.1.2 数组的初始化
//数组初始化 int arr[3][4] = {1,2,3,4}; int arr[3][4] = {{1,2},{4,5}}; int arr[][4] = {{2,3},{4,5}};
花括号中的一个花括号代表一个一维数组的初始化。当里面无花括号分组时,按照顺序从第一个开始逐个进行初始化。余下的未赋值的元素用0初始化。
例如:
int arr3[3][3] = { {1,2},{2,3} };//按照行初始化
存放形式如下:
1 | 2 | 0 |
2 | 3 | 0 |
0 | 0 | 0 |
注:在二维数组的初始化中只能省略行,不能省略列,因为二维数组在空间中是连续存放的,需要知道每一行的起始位置在哪。
3.2 二维数组的使用
二维数组的使用也是通过下标的方式,二维数组是有行和列的,只要锁定了行和列的坐标,用双重循环嵌套进行索引使用。
与一维数组同理,二维数组的下标也是从0开始的。
如下所示:
#include <stdio.h> int main() { int arr[3][4] = { 0 }; int i = 0; for (i = 0; i < 3; i++) { int j = 0; for (j = 0; j < 4; j++) { arr[i][j] = i * 4 + j; } } for (i = 0; i < 3; i++) { int j = 0; for (j = 0; j < 4; j++) { printf("%d ", arr[i][j]); } } return 0; }
编译结果如下:
3.3 二维数组在内存中的存储
我们知道一维数组在内存中是连续存放的,那二维数组在内存中是怎么存放的呢?
#include <stdio.h> int main() { int arr[3][5] = { 0 }; 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; }
结果如下:
通过结果我们可以分析到,其实二维数组在内存中也是连续存储的。
- 二维数组在内存的空间布局上,也是线性连续且递增的!!!
- 二维数组本质上也是一维数组,只不过内部元素放的是一维数组。
四、变长数组
在C99标准之前,C语⾔在创建数组的时候,数组⼤⼩的指定只能使⽤常量、常量表达式,或者如果我们初始化数据的话,可以省略数组⼤⼩。
例如:
1. int arr1[10]; 2. char arr2[4]; 3. int arr3[] = {1,2,3};
但是这样的语法限制,让我们创建数组就不够灵活,有时候数组⼤了浪费空间,有时候数组⼜⼩了不够⽤,所以在C99中给⼀个变⻓数组(variable-length array,简称VLA)的新特性,允许我们可以使⽤变量指定数组⼤⼩。
例如:
1. int n = a+b; 2. int arr[n];
可惜的是在vs2022编译器上不支持这种写法,会发生报错,也就没法给大家演示结果了。