学数组,这一篇就够了

每日一句:

伤害人的并非事件本身,而是他对事件的看法。

戴尔·卡耐基—《人性的弱点》


今日,我们请来了一位老大,别看他只是个人,他能装的东西比你还要多呢。

老大的简介:

(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])。

下面给大家展示一个简单的程序:

#includeint main(){ const int days[]={31,28,31,30,31,30,31,31,30,31};int index;for(index=0;indexprintf("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#define months 12int main (){ int days[months]={31,28,[4]=31,30,31,[1]=29};int i;for(i=0;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#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{ for(month=0,subtot=0;monthsubtot+=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;monthfor(year=0,subtot=0;yearsubtot+=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];

    最后的话

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

    5个超正经的网站

    让它助你完成假期“超车”

    一个正在学习C语言的人,致力于将C讲得更透彻!

    点赞关注~谢谢你~

    长按下图二维码关注,和你一起领悟程序员的魅力。


  • 你可能感兴趣的:(学数组,这一篇就够了)