目录
前言
数组是新手接触c语言学习的一个难点,也是必须要攻克的一个点,在深度学习数组之后可以对学习指针有极大地帮助。
1.数组的概念
数组是一组相同类型元素的集合;从这个概念中我们可以提取两个有价值的信息:
- 数组中存放的是一个或者多个数据,但是元素个数不能为0。
- 数组中存放的多个数据,类型是相同的。
数组分为一维数组和多维数组,多维数组常见的是二维数组。
例如下面代码:
int main(void)
{
float candy[365];//内含365个float类型元素的数组
char code[12];//内含12个char类型元素的数组
int states[50];//内含50个states类型元素的数组
...
}
2.一维数组的创建和初始化
2.1数组创建
一维数组创建的基本语法如下:
type arr_name[常量值];
- type指定的是数组中存放数据的类型,可以是:char,short,int,float等,也可以是自定义的类型。
- arr_name指的是数组名的名字。
- []中的常量值是用来指定数组的大小的,这个数组的大小是根据实际的需求指定就行。
比如:我们现在想存储5门学科的成绩,如下:
int score[5];
2.2数组的初始化
数组在创建的时候,我们需要给定一些初始值,这种就称为初始化。
那数组是如何初始化呢?数组的初始化一般使用大括号,将数据放在大括号中。
int arr[5]={1,2,3,4,5};//完全初始化
int arr2[6]={1};//第一个元素初始化为1,剩下的元素默认为初始化为0
数组初始化常见错误:
int arr3[3]={1,2,3,4}//错误的初始化-初始项太多了
int arr4[6]=(1,2,5,6) //小括号错误
int arr5(3)={1,2,3}//小括号错误
2.3数组的类型
回顾一下我们学过的c语言基本数据类型,int整型(即int类型的值必须是整数),可以有三个关键字来修饰int,如:short int、long int、long long int、unsigned int(非负号);char类型用于储存字符(如:字母或者标点符号);_Bool类型用于表示布尔值,即逻辑值true和false,因为c语言用1表示true,用0表示false,所以_Bool类型实际上是整数类型;浮点类型:float、double、long double等等。数组也是有类型的,数组算是一种自定义类型,去掉数组名留下的就是数组的类型。
如下:
int arr1[10];
int arr2[12];
int ch[5];
arr1数组的类型是int [10],arr2数组的类型是int [12],ch数组的类型是char[5]。
3.一维数组的使用
以上我们学习了一维数组的基本语法,一维数组可以存放数据,存放数据的目的是对数据的操作,那我们该如何g学习一维数组呢?
3.1数组下标
C语言标准是规定C语言是有下标的,下标是从0开始的,假设数组有n个元素,最后一个元素的下标是n-1,下标就相当于数组元素的编号,如下:
int arr[10]={1,2,3,4,5,6,7,8,9,10};
在C语言中数组的访问提供了一个操作符[ ],这个操作符叫:下标引用操作符。
有了下标引用操作符,我们就可以轻松访问数组的元素了,如果你想访问arr[10]里面的9这个元素,我们就可以使用arr[8];想要访问下标为9的元素,我们就这样使用arr[9],注意这两者我的表述是不同的。如下代码:
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", arr[8]);
printf("%d\n", arr[9]);
return 0;
}
输出结果:
3.2数组元素的打印
接下来,如果想访问整个数组的内容,那怎么办呢?
我们把每个数组元素所对应的下标依次打印出来就可以了,依次打印显然会用到循环,在循环节结构中我们学到了for,while,do while三种循环,在这里我们选择for循环产生0-9的下标,如下代码:
#include<stdio.h>
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
输出的结果:
3.3数组的输入
前面说过数组是用来储存元素的,在数组初始化的时候给的元素并没有储存的电脑的地址里去,因为没有用到scanf函数对吧,我们可以结合for循环加上scanf函数,自己给数组输入想要的数据,如下:
#include<stdio.h>
int main()
{
int arr[6] = { 1,2,3,4,5,6 };
int i = 0;
for (i = 0; i < 6; i++)
{
scanf_s("%d", &arr[i]);
}
for (i = 0; i < 6; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
输出结果:
像这种知识点,其实在我们平时练习题目的时候就经常遇到,比如下面这道题:
这道题可以改编为歌手比赛,记录成绩打平均分等;代码如下:
#include<stdio.h>
int main()
{
/*int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };*/
int arr1[10];//可以只自定义不放值进去
int sum = 0;
for (int i = 0; i < 10; i++)
{
scanf_s("%d", &arr1[i]);
}
for (int i = 0; i < 10; i++)
{
sum = sum + arr1[i];
}
printf("%.1f", (float)sum/10);//首先平均值会有小数,要将sum的类型转换
return 0;
}
4.一维数组在内存中的存储
我觉得新手包括我一开始学习C语言最抽象的应该是计算机内存,它无法看到,需要自己去理解。现在我们需要深入了解数组,就需要了解一下数组在内存中的存储。
依次打印数组元素的地址:
#include<stdio.h>
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
for (i = 0; i < 10; i++)
{
printf("arr1[%d]=%p\n", i, &arr1[i]);//&将地址取出来,%P打印地址
}
return 0;
}
通过输出结果我们分析,数组随着下标的增长,地址是由小到大变化的,并且我们发现每两个相邻的元素之间相差4(一个整型是4个字节)。由此观之:数组在内存中是连续存放的。
5.sizeof计算数组元素个数
新手看到这里是不是很纳闷,一开始定义数组的时候,不是都规定好了arr[10]吗?这不是已经表明该数组有10个元素吗。但是谁告诉你数组一开始非要这样定义,这样arr[ ]也是可以的,因此就不知道该数组的元素是多少。我们可以用sizeof来计算数组元素个数。
sizeof是C语言中的一个关键字,是可以计算类型或者变量大小的,其实sizeof也可以计算数组的大小。如:
#include<stdio.h>
int main()
{
int arr[10];
printf("%d\n", sizeof(arr));
return 0;
}
得出的结果是40,单位是字节。因为我们定义的是整型变量,一个整型是4个字节。显然一个数组中的所有元素的数据类型都是相同的,那只要计算出一个元素所占字节的个数,数组的元素个数就能计算出来。先算出一个元素所占字节的多少:
#include<stdio.h>
int main()
{
int arr[10];
printf("%d\n", sizeof(arr[0]));
return 0;
}
接下来就能计算出元素个数:
#include<stdio.h>
int main()
{
int arr[10];
printf("%d\n", sizeof(arr)/sizeof(arr[0]));
return 0;
}
结果为10,表示数组有10个元素。以后在代码中需要数组元素个数的地方就不用固定写死了,使用上面的计算,不管数组怎么变化,计算出的大小也就随着变化了。
6.二维数组的创建
6.1 二维数组的概念
前面学习的数组被称为一维数组,数组的元素都是内置类型的,如果我们把一维数组作为数组的元素,这时候就是二维数组,二维数组作为数组元素的数组被称为三维素组,同理二维数组以上的素组统称为多维数组。
6.2二维数组的创建
那我们如何定义二维数组呢?见一下代码:
type arr_name[常量值1][常量值2];
//例如
int arr[5][3];
double data[2][5];
解释:
- 5数组表示有5行
- 3表示每行有3个元素
- int表示数组的每个元素是整型类型
- arr是数组名,自己定义
7.二维数组的初始化
7.1不完全初始化
int arr1[3][5]={1,2};
int arr2[3][5]={0};
在创建变量或者数组的时候,给定一些初始值,被称为初始化,但像上面代码那样没有给定足够的初始值就被称为不完全初始化。像一维数组一样,也是使用大括号初始化的。
7.2完全初始化
int arr3[3][5]={1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7,};
7.3按照行初始化
int arr4[3][5]={{1,2},{3,4},{5,6}};
每行元素初始化元素不够时,自动填充为0.
7.4初始化时省略行,但是不能省略列
int arr5[][5]={1,2,3};
int arr6[][5]={1,2,3,4,5,6,7};
int arr7[][5]={{1,2},{3,4},{5,6}};
8.二维数组的使用
8.1二维数组的下标
在一维数组中我们利用下标锁定数组中的元素,二维数组中同理,我们只要找准二维数组中的行与列就能锁定数组中的元素,如:arr[1][0]就是第二行第一个元素,因为C语言规定,二维数组的行是从0开始的,列也是从0开始的。
#include<stdio.h>
int main()
{
int arr[3][2] = { 1,2,3,4,5,6 };
printf("%d", arr[1][0]);
return 0;
}
得出的结果是3,验证前面我所论述的内容。
8.2二维数组的输入和输出
8.1小节我们讲的是如何访问数组的单个元素,那怎么访问整个二维数组呢?其实我们只要能够按照一定的规律产生所有的行和列的数字就行:以上一段代码中的arr数组为例,行的选择范围是0-2,列的取值范围是0-1,我们可以借用循环实现生成所有的下标。
int main()
{
int arr[3][2] = { 1,2,3,4,5,6 };
int i = 0;
for (i = 0; i < 3; i++)
{
for (int j = 0; j < 2; j++)
{
scanf_s("%d", &arr[i][j]);
}
}
for (i = 0; i < 3; i++)
{
for (int j = 0; j < 2; j++)
{
printf("%d", arr[i][j]);
}
printf("\n");
}
return 0;
}
输入和输出的结果:
9.二维数组在内存中的存储
存储一定不开地址,像一维数组一样,我们如果想研究二维数组在内存中的存储方式,我们也是可以打印出数组所有元素的地址的。代码如下:
#include<stdio.h>
int main()
{
int arr[3][2];
int i, j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 2; j++)
{
scanf_s("%d", &arr[i][j]);
}
}
for (i = 0; i < 3; i++)
{
for (j = 0; j < 2; j++)
{
printf("&arr[%d][%d]=%p\n", i, j, &arr[i][j]);
}
}
return 0;
}
输出结果:
显然输出结果验证int整型占四个字节空间。同时二维数组中的每个元素都是连续存放的。
10.总结
关于数组的基础知识行文至此已经完结,但是数组的额外与函数,指针相关的知识,本文不做补充,后面我会补充关于数组相关的习题练习。