文章目录
- C语言梦开始的地方6:数组
- 一维数组
- 一维数组的创建
- 一维数组初始化
- 一维数组输入与输出
- sizeof 计算数组元素个数
- 一维数组在内存的存储
- 二维数组
- 二维数组的创建
- 二维数组初始化
- 二维数组输入与输出
- 二维数组计算大小
- 二维数组在内存的存储
- C99变长数组
C语言梦开始的地方6:数组
数组是一组相同类型元素的集合;从这个概念中我们就可以发现2个有价值的信息:
- 数组中存放的是1个或者多个数据,但是数组元素个数不能为0。
- 数组中存放的多个数据,类型是相同的。
数组分为一维数组和多维数组,多维数组一般比较多见的是二维数组
一维数组
一维数组的创建
一维数组的创建
type arr_name[常量值];存放在数组的值被称为数组的元素,数组在创建的时候可以指定数组的大小和数组的元素类型。
- type 指定的是数组中存放数据的类型,可以是: char、short、int、float 等,也可以自
定义的类型。- arr_name 指的是数组名的名字,这个名字根据实际情况,起的有意义就行。
- [] 中的常量值是用来指定数组的大小的,这个数组的大小是根据实际的需求指定就行
比如我想统计一下班级上20个同学的名字:char name[20];除上述以外我们可以根据不同需求来进行创建不同类型和大小的一维数组:
double score[20]; int id[20];数组类型算是一种自定义类型,去掉数组名留下的就是数组的类型
比如说:int arr[10]; -》int [10] char arr2[10]; -》char [10] 以此类推bool类型也可以,我们给0就是false,给1就是true(给任何非零值都可以,C语言普遍是给1)
一维数组初始化
上述是我们对一维数组的简单了解,现在我们开始了解一下一维数组的初始化操作
一维数组的初始化操作分:完全初始化,不完全初始化
#include<stdio.h>intmain(){// 完全初始化intarr1[5]={1,2,3,4,5};// 不完全初始化intarr2[5]={1};//第一个元素初始化为1,剩余的元素默认初始化为0return0;}arr1输出是1,2,3,4,5
arr2输出是1,0,0,0,0
在初始化数组时一定不要输入超出数组给出的范围大小不然就会越界报错
比如:int arr3[4] = {1,2,3,4,5};这种就会之间报错
如果不知道数组范围大小或者没有想清楚我们可以这样来写
#defineCAPACITY10intmain(){intarr1[CAPCITY]={1,2,3,4,5,6};// 或者这样intarr2[]={1,2,3,4,5,6};return0;}第一种写法:#define CAPACITY 10 是预处理指令(以 # 开头)。
它不参与编译,而是在编译之前(预处理阶段),由预处理器把代码中所有写有 CAPACITY 的地方,机械地、原封不动地替换成 10,简单了解就是#define在这里就是文本替换
第二种写法:不给范围让编译器来自己去计算大小
这两种写法都可以满足我们在不知道给多少范围时使用,第一种会更加灵活因为大了我们直接修改capcity的值即可,小了同理。
一维数组输入与输出
一维数组同样可以进行输入输出操作,不过和我们平时输入输出不一样
平时的输入: scanf("%d",&n); 数组的输入: scanf("%d",&arr1[i]);我们需要先知道数组的下标才能进行正常的输入和输出操作,但是数组的下标并不是从1开始而是从0开始
所以输入和输出都是从0开始一直到数组的结尾部,如果一个数组长度为n,那么就是要到n - 1处。
在C语言中数组的访问提供了一个操作符[] ,这个操作符叫:下标引用操作符。
intmain(){intarr1[10];for(inti=0;i<10;++i){scanf("%d",&arr1[i]);}for(inti=0;i<10;++i){printf("arr1[%d]: %d ",i,arr1[i]);}return0;}sizeof 计算数组元素个数
当我们不知道数组的个数时,此时我们还需要遍历数组时我们就可以通过
sizeof来计算他的大小,sizeof不仅能计算出类型的大小并且也可以计算数组的大小。
sizeof计算的单位是字节
intmain(){intarr1[10];intsize=sizeof(arr1);printf("%d\n",size);intn=sizeof(arr1)/sizeof(arr1[0]);printf("%d\n",n);return0;}这里size是40的原因是一个int类型占4个字节,那么n的结果就好理解了 40 / 4 = 10。
一维数组在内存的存储
有了前面的知识,我们其实使用数组基本没有什么障碍了,如果我们要深入了解数组,我们最好能了解一下数组在内存中的存储。
依次打印数组元素的地址:
intmain(){intarr1[10]={1,2,3,4,5,6,7,8,9,10};for(inti=0;i<10;++i){printf("arr1[%d]: %p\n",i,&arr1[i]);}return0;}从输出的结果我们分析,数组随着下标的增长,地址是由小到大变化的,并且我们发现每两个相邻的元素之间相差4(因为一个整型是4个字节)。所以我们得出结论:数组在内存中是连续存放的。
二维数组
上述是我们对一维数组的了解,现在我们开始了解多维数组,多维数组中使用的最多就是二维数组,所以我们只需重点了解二维数组即可
二维数组的创建
二维数组创建的语法格式:
type arr_name[常量值1][常量值2]; 例如: int arr[3][5]; double data[2][8];相比一维数组 int arr[3]; 多了一个[5],那么三维数组就是比二维数组多了一个[],以此类推.
上述代码解释:
- 3表示数组有3行
- 5表示每一行有5个元素
- int 表示数组的每个元素是整型类型
- arr是数组名,可以根据自己的需要指定名字
二维数组初始化
二维数组的初始化和一维数组初始化同样也分完全初始化和不完全初始化
不完全初始化 int arr1[3][5] = {1,2}; int arr2[3][5] = {0}; 完全初始化:两种写法 第一种:int arr3[3][5] = {1,2,3,4,5, 2,3,4,5,6, 1 3,4,5,6,7};还有一种初始化叫
按行初始化,这种初始化可读性更高并且不完全初始化也可按照按行初始化这样初始化
#include<stdio.h>#include<stdio.h>intmain(){// 不完全初始化intarr1[3][5]={1,2};intarr2[3][5]={0};// 不完全初始化的按行初始化intarr3[3][5]={{1,2}};// 完全初始化intarr4[3][5]={1,2,3,4,5,2,3,4,5,6,3,4,5,6,7};// 完全初始化的按行初始化intarr5[3][5]={{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}};return0;}二维数组输入与输出
同样二维数组的输入输出相比一维也只多了一个[]
intmain(){intarr[3][5];inti=0;for(i=0;i<3;i++)// 产生行号{intj=0;for(j=0;j<5;j++)// 产生列号{scanf("%d",&arr[i][j]);// 输入数据}}// 输出for(i=0;i<3;i++)// 产生行号{intj=0;for(j=0;j<5;j++)// 产生列号{printf("%d ",arr[i][j]);// 输出数据}printf("\n");}return0;}二维数组计算大小
二维数组计算大小的方式和一维数组一样都是通过sizeof关键字来计算的,二维数组计算方式如下:
intmain(){intarr[3][5];introw=sizeof(arr)/sizeof(arr[0]);intcol=sizeof(arr[0])/sizeof(arr[0][0]);printf("row: %d,col: %d\n",row,col);}sizeof(arr) = 60 = 4 * 15,4是int类型的所占大小,15是arr能存入的范围
sizeof(arr[0]) = 20 = 4 * 5,5是当前行的所存入范围
sizeof(arr[0][0]) = 4,这个等价于一维数组的sizeof(arr[0])只计算了当前元素的所占大小
二维数组在内存的存储
和处理一维数组一样的打印出二维数组每一个元素的内存地址:
intmain(){intarr[3][5]={0};inti=0;intj=0;for(i=0;i<3;i++){for(j=0;j<5;j++){printf("&arr[%d][%d] = %p\n",i,j,&arr[i][j]);}}return0;}从输出的结果来看,每一行内部的每个元素都是相邻的,地址之间相差4个字节,跨行位置处的两个元素(如:arr[0][4]和arr[1][0])之间也是差4个字节,所以二维数组中的每个元素都是连续存放的。
所以我们可以得出一个结论:二维数组在底层实现上是由多个一维数组组成的因为它的每行的末尾和下一行的开头的地址是连续的。
C99变长数组
在C99标准之前,C语言在创建数组的时候,数组大小的指定只能使用常量、常量表达式,或者如果我们初始化数据的话,可以省略数组大小。
这样的语法限制,让我们创建数组就不够灵活,有时候数组大了浪费空间,有时候数组又小了不够用的。
C99中给一个变长数组(variable-length array,简称 VLA)的新特性,允许我们可以使用变量指定数组大小。
变长输出的语法格式是:类型 数组名[运行时整型表达式]; 比如: int n = a + b; int arr[n];需注意的是该语法只能在变长数组语法的编译器上才能使用,因为变长数组在有的C语言大佬看来是破坏C语言的一种语法,所以有可能当前的编译器支持c99但是不支持c99的变长数组
该内容只作了解即可,后续我们会了解当更好的方式比如去向堆区申请内存的方式就能完美替代这种语法
#include<stdio.h>intmain(){intn;printf("请输入数组大小: ");scanf("%d",&n);// 语法:使用变量 n 作为长度(运行时确定)intarr[n];// 填充并打印数组for(inti=0;i<n;i++){arr[i]=i*10;printf("%d ",arr[i]);}// 输出(假设输入5):0 10 20 30 40return0;}完