学数组,这一篇就够了

“伤害人的并非事件本身,而是他对事件的看法。” 戴尔·卡耐基—《人性的弱点》

今日,我们请来了一位老大,别看他只是个人,他能装的东西比你还要多呢。
在这里插入图片描述

这位老大叫什么呢,等一下再说啊,老大的名字可不是能随便乱说的

老大的简介:

(array)是按顺序储存的一系列相同的值,可以是10个char类型的字符或15个int类型的值。没错,这位老大便是数组。这位老大还是有许多小弟的,这些小弟姓什么呢,有个专门的名字叫元素。没错,整个数组有一个数组名,通过整数下标访问数组中单独的项或元素(element)。

如何定义数组呢:

**

int name[10];//说明可存储10个int类型整数的数组
char name[10];//说明可存储10个字符的数组

**

老大介绍得差不多了,那么接下来便是介绍小弟(数组里的元素)了。小弟可是很厉害的呢,它可以是任意数据类型哦。

我们将用于识别数组元素的数字称为下标(subscript),索引(indice),或偏移量(offset)。需要注意的是下标必须是整数哦,下标中的整数也代表了数组中有多少元素,而且要从0开始计数。下标也是存在陷阱的,因为怕影响到执行的速度,C编译器是不会检查数组的下标是否正确的哦。而且数组的元素是被依次存在内存中相邻的位置。

**

int name[10];//元素为name[0]~name[9]
name[10]=55;//这个便是错的,该数组元素不存在

**

注意:每个int为2字节,char为1字节。顺便扩展一下位、字,字节与KB的关系:

KB 1KB=1024B

MB 1MB=1024KB

GB 1GB=1024MB

TB 1TB=1024GB

int类型数组元素的用法和int类型变量的用法类似,比如要读取int类型变量name,应该这样写

**

scanf("%d",&name);//读取变量
scanf("%d",&name[n]);//读取数组

**

昨天我们运用了许多的for循环,就有小伙伴跟我说那么多for可以独立出来写么,独立的for循环我个人不建议。将for循环合并成一个循环可以使程序显得更加紧凑,但我们也要遵循模块化的原理。模块化主要是把程序划分为一些独立的单元,每个单元执行一个任务,这样也能提高程序的可读性。更重要的是模块化使程序的不同部分彼此独立,方便以后对程序的修改。

当我们定义数组后,该如何赋值呢:

**

int name[5]={
    
    1,2,3,4,5};
int name[5]={
    
    1,2,3,4};

**

我们认真看就会发现第一行和第二行的差别,第一行将5个值赋给了name,而第二行却只有4个数值,那么还差一个怎么办呢?不用怕,编译器会为它补上0的,但也只能补0哦。

接下来我们就来更加详细的介绍数组:

初始化数组

数组通常被用来存储程序需要的数据。比如一个内含12个整数元素的数组就可以存储12个月的天数。在这种情况下,在程序一开始就初始化数组比较好。大家知道什么是标量变量么,简单说就是只存储单个值的变量。接下来我们来初始化这种变量:

**

float flax=PI*2;/*PI已定义为宏*/
初始化数组:
int main()
{
    
    int name[5]={
    
    1,2,3,4,5};
...}

**

如上所示,我们用以逗号分隔的值列表(用花括号括起来的)来初始化数组,各值之间用逗号分隔,在逗号和值之间可以有空格。上面的初始化是把1赋值给数组的首元素(即name[0])。
下面给大家展示一个简单的程序:

**

#include<stdio.h>
int main()
{
    
     const int days[]={
    
    31,28,31,30,31,30,31,31,30,31};
int index;
for(index=0;index<sizeof day/sizeof days[0];index++)
printf("Month %2d has %d days.\n",index+1,days[index]);
return 0;
}

**

运行结果如图:

在这里插入图片描述

这里需要注意如下几点:

NO.1我们在上面初始化数组时是省略了方括号中的数字,编译器会根据初始化列表中的项数来确定数组的大小。

NO.2 Sizeof运算符给了它运算对象的大小(以字节为单位)。使用Sizeof days 是整个数组的大小,Sizeof day[0]是数组中元素的大小。整个数组的大小除以单个元素的大小就是数组元素的个数。

指定初始化器

C99多了一个新特性:指定初始化器。利用该特性可以初始化指定的数组元素。

例如可以在初始化列表中使用带方括号的下标指明待初始化的元素:

int shu[6]={[5]=55};//把shu[5]初始化为55

一般来说,在初始化一个元素后,没有被初始化的元素都会被设置为0。以下面程序为例:

**

#include<stdio.h>
#define months 12
int main ()
{
    
     int days[months]={
    
    31,28,[4]=31,30,31,[1]=29};
int i;
for(i=0;i<months;i++)
{
    
    printf("%2d %d\n",i+1,days[i]);}
return 0;
}

**

运行如下:
在这里插入图片描述

该程序需要注意以下几点(需要多多思考哦):

NO.1 如果指定初始化器后面有更多的值,如该例中的初始化列表中的片段:[4]=31,30,31,那么后面这些值将被用于初始化为30和31.

NO.2 如果再次初始化指定的元素,那么最后的初始化将会取代之前的初始化。比如上面的程序中初始化列表开始时把days[1]初始化为28,,但是days[1]又被后面的指定初始化[1]=29初始化为29.

NO.3 说到如果没有指定元素大小会怎样呢?如下:

**

int shu[]={1,[6]=2};//该数组有7个元素
int shu[]={1,[6]=2,3};//该数组有8个元素

**

即:编译器会把数组的大小设置为足够装得下初始化的值。

数组边界

我们在使用数组时,要防止数组下标越过边界。简单来说就是确保下标是有效的值。比如:

int you[20];
在使用该数组时,就需要注意在程序中使用的数组下标在0~19的范围内,况且编译器不会检查出这种错误。前面也说到过。

因此,使用越界的数组下标会导致程序改变其他变量的值。不同的编译器运行该程序的结果可能也会不同哦,有的甚至会导致程序异常中止。

还要记住一点就是数组元素的编号是从0开始的哦,最好是在声明数组时使用符号常量来表示数组的大小。

数组下标

C99标准允许了一种新型的声明方式:

int a1[n];//c99之前是不允许这样的哦
这创建了一种新型数组,称为变长数组。简称VLA(C11放弃了这一举措,把VLA设定为可选,而不是语言必备的特性)

C99引入变长数组主要是为了让C成为更好的数值计算语言。

注意:变长数组是指用整型变量或表达式声明或定义的数组,而不是说数组的长度会随时变化,变长数组在其生存期内的长度同样是固定的。

多维数组

上面把数组介绍得差不多了,那么下面就开始介绍二维和多维数组。我们可以把一维数组想象成一行数据,把二维数组想象成数据表,把三维数组想象成一叠数据表。

现在用一个项目来讲解二维数组:

如果有一个气象员想要收集5年内每个月的降水量数据,那么他要如何表示数据呢?一个方案是创建60个变量,每个变量存储一个数据项,显然这个方法太麻烦。那么我们就可以用到二维数组来解决,即创建一个主数组,主数组含有5个元素,每个元素是内含12个元素的数组(每个元素表示一个月)。

声明数组如下:

float rain[5][12];
//内含5个数组元素的数组,每个数组元素内含12个float类型的元素
float rain[5][12]  //颜色部分是指rain是一个内含5个元素的数组;非颜色部分则是指一个含有12个float类型元素的数组。

这说明每个元素的类型都是float[12],简单说也就是rain的每个元素本身都是一个内含12个float类型值的数组。那么rain[0]是一个数组,它的首元素就是rain[0][0],第二个便是rain[0][1],以此类推。

该项目代码如下:

#include<stdio.h>
#define months 12//12个月
#define years 5//年数
int main()
{
    
    const float rain[years][months]={
    
    
{
    
    4.3,4.3,4.3,3.0,2.0,1.2,0.2,0.2,0.4,2.4,3.5,6.6},
{
    
    4.1,4.3,4.3,3.0,2.0,1.2,0.2,0.2,0.4,2.4,3.5,6.6},
{
    
    4.3,4.3,4.3,3.0,2.0,1.2,0.2,0.2,0.4,2.4,3.5,6.6},
{
    
    4.3,4.3,4.3,3.0,2.0,1.2,0.2,0.2,0.4,2.4,3.5,6.6},
{
    
    4.3,4.3,4.3,3.0,2.0,1.2,0.2,0.2,0.4,2.4,3.5,6.6},
};//初始化时可省略内部的花括号,只要保证初始化的数值个数正确
int year,month;
float subtot,total;
printf("year    rainfall   (inches)\n");
for (year=0,total=0;year<years;year++)//每一年,各月的降水量总和
{
    
     for(month=0,subtot=0;month<months;month++)
subtot+=rain[year][month];
printf("%5d %15.1f\n",2015+year,subtot);
total+=subtot;} //5年的总降水量
printf("\nThe yearly average is %.1f inches.\n\n",total/years);
printf("monthly averages:\n\n");
printf("Jan Feb Mar Apr May Jun Jul Aug Sep Oct");
printf("Nov Dec\n");
for(month=0;month<months;month++){
    
    
for(year=0,subtot=0;year<years;year++)
subtot+=rain[year][month];
printf("%4.1f",subtot/years);
}
printf("\n");
return 0;
}

运行结果如下:

在这里插入图片描述

此程序计算了每年的总降水量,年平均降水量和月平均降水量。

该程序使用了两个嵌套for循环,第一个是嵌套for循环的内层循环,在year不变的情况下,遍历month计算某年的总降水量;外层循环则改变year的值,重复遍历month,计算五年的总降水量。

这里我们可以看到处理二维数组需要处理用到2重嵌套循环,通常来说,处理三维数组需要用到3重嵌套循环,四维则需要用到4重嵌套循环。

我们说的二维数组的许多相关内容都适用于三维或者多维数组。比如声明一个三维数组如下:

int name [3][3][3];

最后的话

相信你学到这里或多或少都对数组有了一定的了解,想要更好的理解数组,建议多看几遍哦。这也是经过多次阅读书籍从而整理出来数组里最重要的一些知识点。希望大家看完这篇文章后对数组有更好的了解。

公众号:程序员Bob
一个正在学习的大学生,欢迎关注和我一起交流哦!
点赞关注~谢谢

猜你喜欢

转载自blog.csdn.net/m0_46259251/article/details/104706657