资源预览内容
第1页 / 共64页
第2页 / 共64页
第3页 / 共64页
第4页 / 共64页
第5页 / 共64页
第6页 / 共64页
第7页 / 共64页
第8页 / 共64页
第9页 / 共64页
第10页 / 共64页
亲,该文档总共64页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
单片机单片机C C语言开发技术语言开发技术内容概述内容概述数数组组是是一一种种构构造造类类型型的的数数据据,通通常常用用来来处处理理具具有有相相同同属属性性的的一一批批数数据据。本本章章主主要要介介绍绍一一维维数数组组、二二维维数数组组、多多维维数数组组以以及及字字符符数数组组的的定定义、初始化、引用及应用。义、初始化、引用及应用。6.1.3一维数组的初始化对数组元素的初始化可以用以下方法实现:1)在定义数组时对数组元素赋以初值。例如:inta10=0,1,2,3,4,5,6,7,8,9;2)可以只给一部分元素赋值。例如:inta10=0,1,2,3,4;定义a数组有10个元素,但花括弧内只提供5个初值,这表示只给前面5个元素赋初值,后5个元素值为0。3)如果想使一个数组中全部元素值为0,可以写成inta10=0,0,0,0,0,0,0,0,0,0;不能写成inta10=0*10;4)在对全部数组元素赋初值时,可以不指定数组长度。例如:inta5=1,2,3,4,5;可以写成inta=1,2,3,4,56.1.4一维数组应用举例一维数组应用举例v例6-1-2已知某课程的平时、实习、测验和期末成绩,求该课程的总评成绩。其中平时、实习、测验和期末分别占10、20、20、50。#include#includevoidmain(void)inti=1,j;charcon_key=x20;/x20空格键的ASCII码floatscore5,ratio4=0.1,0.2,0.2,0.5;/*定义成绩、比例系数数组*/#ifndefMONITOR51/*需要从串口1输出时请作如下设置*/SCON=0x50;/*方式1,允许接收*/TMOD|=0x20;/*TMOD:定时器1方式2*/TH1=221;/*1200bps16MHz*/TR1=1;/*启动定时器1*/TI=1;/*KeilC自带的puchar()函数需要设置TI1*/#endifwhile(con_key=x20)printf(输入第%2d个学生的成绩n,i+);printf(平时实习测验期末成绩n);score4=0;/*score4:存储总评成绩*/for(j=0;j4;j+)scanf(%f,&scorej);score4+=scorej*ratioj;printf(总评成绩为:%6.1fn,score4);getchar();6.2二维数组6.2.1二维数组的定义v二维数组定义的一般形式为类型说明符类型说明符数组名常量表达式常量表达式数组名常量表达式常量表达式例如:floata34,b510;v不能写成floata3,4,b5,10;6.2.2二维数组元素的引用引用二2维数组元素的形式为:数组名数组名行下标表达式行下标表达式列下标表达式列下标表达式1“行下标表达式”和“列下标表达式”,都应是整型表达式或符号常量。2“行下标表达式”和“列下标表达式”的值,都应在已定义数组大小的范围内。假设有数组x34,则可用的行下标范围为02,列下标范围为03。3对基本数据类型的变量所能进行的操作,也都适合于相同数据类型的二维数组元素。6.2.3二维数组的初始化1按行赋初值数据类型数据类型数组名数组名行常量表达式行常量表达式列常量表达式列常量表达式第第0行初值表行初值表,第第1行初值表行初值表,最后最后1行初值表行初值表;v赋值规则:将”第0行初值表”中的数据,依次赋给第0行中各元素;将“第1行初值表”中的数据,依次赋给第1行各元素;以此类推。2按二维数组在内存中的排列顺序给各元素赋初值数据类型数据类型数组名数组名行常量表达式行常量表达式列常量表达式列常量表达式初值表初值表;v赋值规则:按二维数组在内存中的排列顺序,将初值表中的数据,依次赋给各元素。v如果对全部元素都赋初值,则“行数”可以省略。v注意:只能省略“行数”。6.2.4二维数组应用举例v例6-2-1有M个学生,学习N门课程,已知所有学生的各科成绩,编程:分别求每个学生的平均成绩和每门课程的平均成绩。#defineNUM_std5/*定义符号常量人数为5*/#defineNUM_course4/*定义符号常量课程为4*/#includemain()inti,j;staticxdatafloatscoreNUM_std+1NUM_course+1=78,85,83,65,88,91,89,93,72,65,54,75,86,88,75,60,69,60,50,72;for(i=0;iNUM_std;i+)for(j=0;jNUM_course;j+)scoreiNUM_course+=scoreij;/*求第i个人的总成绩*/scoreNUM_stdj+=scoreij;/*求第j门课的总成绩*/scoreiNUM_course/=NUM_course;/*求第i个人的平均成绩*/for(j=0;jNUM_course;j+)scoreNUM_stdj/=NUM_std;/*求第求第j门课的平均成绩门课的平均成绩*/*输出表头输出表头*/printf(学生编号学生编号课程课程1课程课程2课程课程3课程课程4个人平均个人平均n);/*输出每个学生的各科成绩和平均成绩输出每个学生的各科成绩和平均成绩*/for(i=0;iNUM_std;i+)printf(学生学生%dt,i+1);for(j=0;jNUM_course+1;j+)printf(%6.1ft,scoreij);printf(n);/*输出输出1条短划线条短划线*/for(j=0;j8*(NUM_course+2);j+)printf(-);printf(n课程平均课程平均);/*输出每门课程的平均成绩输出每门课程的平均成绩*/for(j=0;jNUM_course;j+)printf(%6.1ft,scoreNUM_stdj);printf(n);6.3字符数组v用来存放字符量的数组称为字符数组。v字符数组类型说明的形式与前面介绍的数值数组相同。例如:1.charc10;2.charc510;/即为二维字符数组。字符数组也允许在类型说明时作初始化赋值。3.staticcharc=c,p,r,o,g,r,a,m;/当对全体元素赋初值时也可以省去长度说明v例6-3-1定义一个二维数组,在放字符串“BASIC”、“DBASE”,并输出。#includevoidmain(void)inti,j;chara5=B,A,S,I,C,d,B,A,S,E;for(i=0;i=1;i+)for(j=0;j=4;j+)printf(%c,aij);printf(n);v字符串在语言中没有专门的字符串变量,通常用一个字符数组来存放一个字符串。v字符串总是以0作为串的结束符。因此当把一个字符串存入一个数组时,也把结束符0存入数组,并以此作为该字符串是否结束的标志。v有了0标志后,就不必再用字符数组的长度来判断字符串的长度了。vC51语言允许用字符串的方式对数组作初始化赋值。例如:staticcharc=c,p,r,o,g,r,a,m;可写为:staticcharc=Cprogram;或去掉写为:sraticcharc=Cprogram;v用字符串方式赋值比用字符逐个赋值要多占一个字节,用于存放字符串结束标志0。v除了上述用字符串赋初值的办法外,还可用printf函数和scanf函数一次性输出输入一个字符数组中的字符串,而不必使用循环语句逐个地输入输出每个字符。voidmain()staticcharc=BASICndBASE;printf(%sn,c);v注意在本例的printf函数中,使用的格式字符串为“%s”,表示输出的是一个字符串。而在输出表列中给出数组名则可。不能写为:printf(%s,c);6.4多维数组v多维数组的一般说明格式是:类型类型数组名数组名第第n维长度维长度第第n-1维长度维长度.第第1维长度维长度;例如例如:intm32;/*定义一个整数型的二维数组定义一个整数型的二维数组*/charc223;/*定义一个字符型的三维数组定义一个字符型的三维数组*/v数组m32共有3*2=6个元素,顺序为:m00,m01,m10,m11,m20,m21;v数组c223共有2*2*3=12个元素,顺序为:c000,c001,c002,c010,c011,c012,c100,c101,c102,c110,c111,c112,v数组占用的内存空间数组占用的内存空间(即字节数即字节数)的计算式为的计算式为:字节数字节数=第第1维长度维长度*第第2维长度维长度*.*第第n维长度维长度*该数组数据类型占用的字节数该数组数据类型占用的字节数vC51中数组进行初始化有下述规则:1)数组的每一行初始化赋值用“”并用“,”分开,总的再加一对“”括起来,最后以;表示结束。2)多维数组存储是连续的,因此可以用一维数组初始化的办法来初始化多维数组。3)对数组初始化时,如果初值表中的数据个数比数组元素少,则不足的数组元素用0来填补。6.5指针6.51指针和地址6.5.1.1指针变量的定义vC51语言中,对于变量的访问形式之一,就是先求出变量的地址,然后再通过地址对它进行访问,这就是这里所要论述的指针及其指针变量。v所谓变量的指针,实际上指变量的地址v变量的地址虽然在形式上好象类似于整数,但在概念上不同于以前介绍过的整数,它属于一种新的数据类型,即指针类型。vC51中,一般用“指针”来指明这样一个表达式&x的类型,而用“地址”作为它的值,也就是说,若x为一整型变量,则表达式&x的类型是指向整数的指针,而它的值是变量x的地址。v同样,若doubled;则&d的类型是指向双精度数d的指针,而&d的值是双精度变量d的地址。所以,指针和地址是用来叙述一个对象的两个方面。v&x、&d的类型是不同的,一个是指向整型变量x的指针,而另一个则是指向双精度变量d的指针。v指针变量的一般定义为:类型标识符类型标识符*标识符标识符;v其中标识符是指针变量的名字,标识符前加了“*”号,表示该变量是指针变量v“类型标识符”表示该指针变量所指向的变量的类型。v一个指针变量只能指向同一种类型的变量v定义一个指针类型的变量。int*ip;v首先说明了它是一指针类型的变量首先说明了它是一指针类型的变量,注意在定注意在定义中不要漏写符号义中不要漏写符号“*”,否则它为一般的整型否则它为一般的整型变量了。变量了。v另外另外,在定义中的在定义中的int表示该指针变量为指向表示该指针变量为指向整型数的指针类型的变量整型数的指针类型的变量,有时也可称有时也可称ip为指为指向整数的指针。向整数的指针。vip是一个变量是一个变量,它专门存放整型变量的地址。它专门存放整型变量的地址。v指针变量在定义中允许带初始化项。如:inti,*ip=&i;。C51中规定,当指针值为零时,指针不指向任何有效数据,有时也称指针为空指6.5.1.2指针变量的引用既然在指针变量中只能存放地址,因此,在使用中不要将一个整数赋给一指针变量.下面的赋值是不合法的:int*ip;ip=100;假设:inti=200,x;int*ip;可以把i的地址赋给ip:ip=&i;此时指针变量ip指向整型变量i,假设变量i的地址为1800,这个赋值可形象理解为下图所示的联系。ipi1800200图5-1-1给指针变量赋值v以后我们便可以通过指针变量ip间接访问变量i,例如:x=*ip;v运算符*访问以ip为地址的存贮区域,而ip中存放的是变量i的地址,因此,*ip访问的是地址为1800的存贮区域(因为是整数,实际上是从1800开始的两个字节),它就是i所占用的存贮区域,所以上面的赋值表达式等价于x=i;v另外,指针变量和一般变量一样,存放在它们之中的值是可以改变的,也就是说可以改变它们的指向,假设inti,j,*p1,*p2;i=a;j=b;p1=&i;p2=&j;v则建立如图5-1-2所示的联系:p1iap2ib图5-1-2赋值运算结果v这时赋值表达式:p2=p1;v就使p2与p1指向同一对象i,此时*p2就等价于i,而不是j,图5-1-2就变成图5-1-3所示:p1iap2jb图5-1-3p2=p1时的情形v如果执行如下表达式:*p2=*p1;v则表示把p1指向的内容赋给p2所指的区域,此时图5-1-2就变成图5-1-4所示:p1iap2ja图5-1-4*p2=*p1时的情形由于指针是变量,我们可以通过改变它们的指向,以间接访问不同的变量,这给程序员带来灵活性,也使程序代码编写得更为简洁和有效。指针变量可出现在表达式中,设:intx,y*px=&x;指针变量px指向整数x,则*px可出现在x能出现的任何地方。例如:y=*px+5;/*表示把x的内容加5并赋给y*/y=+*px;/*px的内容加上1之后赋给y,+*px相当于+(px)*/y=*px+;/*相当于y=*px;px+*/6.5.1.3地址运算指针允许的运算方式有:1)指针在一定条件下,可进行比较,这里所说的一定条件,是指两个指针指向同一个对象才有意义,例如两个指针变量p,q指向同一数组,则,=,=,=等关系运算符都能正常进行。若p=q为真,则表示p,q指向数组的同一元素;若pq为真,则表示p所指向的数组元素在q所指向的数组元素之前(对于指向数组元素的指针在下面将作详细讨论)。2)指针和整数可进行加、减运算。设p是指向某一数组元素的指针,开始时指向数组的第0号元素,设n为一整数,则:p+n就表示指向数组的第n号元素(下标为n的元素)。不论指针变量指向何种数据类型,指针和整数进行加、减运算时,编译程序总根据所指对象的数据长度对n放大在一般微机上,char放大因子为1,int、short放大因子为2,long和float放大因子为4,double放大因子为8。3)两个指针变量在一定条件下,可进行减法运算。设p,q指向同一数组,则p-q的绝对值表示p所指对象与q所指对象之间的元素个数。其相减的结果遵守对象类型的字节长度进行缩小的规则。6.5.2指针和数组v指针和数组有着密切的关系,任何能由数组下标完成的操作也都可用指针来实现,但程序中使用指针可使代码更紧凑、更灵活。6.5.2.1.指向数组元素的指针定义一个整型数组和一个指向整型的指针变量:inta10,*p;和前面介绍过的方法相同,可以使整型指针p指向数组中任何一个元素,假定给出赋值运算p=&a0;此时,p指向数组中的第0号元素,即a0,指针变量p中包含了数组元素a0的地址,由于数组元素在内存中是连续存放的,因此,我们就可以通过指针变量p及其有关运算间接访问数组中的任何一个元素。C51中,数组名是数组的第0号元素的地址,因此下面两个语句是等价的: p=&a0;p=a;根据地址运算规则,a+1为a1的地址,a+i就为ai的地址。下面我们用指针给出数组元素的地址和内容的几种表示形式。1)p+i和a+i均表示ai的地址,或者讲,它们均指向数组第i号元素,即指向ai。2)*(p+i)和*(a+i)都表示p+i和a+i所指对象的内容,即为ai。3)指向数组元素的指针,也可以表示成数组的形式,也就是说,它允许指针变量带下标,如pi与*(p+i)等价。假若:p=a+5;则p2就相当于*(p+2),由于p指向a5,所以p2就相当于a7。而p-3就相当于*(p-3),它表示a2。6.5.2.2.指向二维数组的指针1二维数组元素的地址为了说明问题,我们定义以下二维数组:inta34=0,1,2,3,4,5,6,7,8,9,10,11;a为二维数组名,此数组有3行4列,共12个元素。但也可这样来理解,数组a由三个元素组成:a0,a1,a2,每个元素又是一个一维数组,且都含有4个元素(相当于4列),例如,a0所代表的一维数组所包含的4个元素为a00,a01,a02,a03。如图5-1-5所示。但从二维数组的角度来看,a代表二维数组的首地址,当然也可看成是二维数组第0行的首地址。a+1就代表第1行的首地址,a+2就代表第2行的首地址。如果此二维数组的首地址为1000,由于第0行有4个整型元素,所以a+1为1008,a+2也就为1016,如图5-1-6所示。v既然我们把a0,a1,a2看成是一维数组名,可以认为它们分别代表它们所对应的数组的首地址.a0代表第0行中第0列元素的地址,即&a00,a1是第1行中第0列元素的地址,即&a10,根据地址运算规则,a0+1即代表第0行第1列元素的地址,即&a01,一般而言,ai+j即代表第i行第j列元素的地址,即&aij。另外,在二维数组中,我们还可用指针的形式来表示各元素的地址。如前所述,a0与*(a+0)等价,a1与*(a+1)等价,因此ai+j就与*(a+i)+j等价,它表示数组元素aij的地址。因此,二维数组元素aij可表示成*(ai+j)或*(*(a+i)+j),它们都与aij等价,或者还可写成(*(a+i)j。另外,要补充说明一下,如果你编写一个程序输出打印a和*a,你可发现它们的值是相同的,这是为什么呢?我们可这样来理解:首先,为了说明问题,我们把二维数组人为地看成由三个数组元素a0,a1,a2组成,将a0,a1,a2看成是数组名它们又分别是由4个元素组成的一维数组。因此,a表示数组第0行的地址,而*a即为a0,它是数组名,当然还是地址,它就是数组第0行第0列元素的地址。2指向一个由n个元素所组成的数组指针v在C51中,可定义如下的指针变量:int(*p)3;v指针p为指向一个由3个元素所组成的整型数组指针。v在定义中,圆括号是不能少的,否则它是指针数组。v这种数组的指针不同于前面介绍的整型指针,当整型指针指向一个整型数组的元素时,进行指针(地址)加1运算,表示指向数组的下一个元素,此时地址值增加了2(因为放大因子为2),而如上所定义的指向一个由3个元素组成的数组指针,进行地址加1运算时,其地址值增加了6(放大因子为23=6),这种数组指针在C51中用得较少,但在处理二维数组时,还是很方便的。例如:inta34,(*p)4;p=a;v开始时p指向二维数组第0行,当进行p+1运算时,根据地址运算规则,此时放大因子为42=8,所以此时正好指向二维数组的第1行。v和二维数组元素地址计算的规则一样,*p+1指向a01,*(p+i)+j则指向数组元素aij。例6-5-1利用指针输出二维数组中的元素。#includeinta34=1,3,5,7,9,11,13,15,17,19,21,23;main()inti,(*b)4;b=a+1;/*b指向二维数组的第1行,此时*b0或*b是a10*/for(i=1;i=4;b=b0+2,i+)/*修改b的指向,每次增加2*/printf(%dt,*b0);printf(n);for(i=0;i2;i+)b=a+i;/*修改b的指向,每次跳过二维数组的一行*/printf(%dt,*(bi+1);printf(n);程序运行结果如下:6.5.3字符指针字符指针在程序中如出现字符串常量在程序中如出现字符串常量,C51编译程编译程序就给字符串常量按排一存贮区域序就给字符串常量按排一存贮区域,这个区这个区域是静态的域是静态的,在整个程序运行的过程中始终在整个程序运行的过程中始终占用。占用。字符串常量的长度是指该字符串的字符字符串常量的长度是指该字符串的字符个数个数,但在按排存贮区域时但在按排存贮区域时,C编译程序还自编译程序还自动给该字符串序列的末尾加上一个空字符动给该字符串序列的末尾加上一个空字符0,用来标志字符串的结束。用来标志字符串的结束。因此一个字符串常量所占的存贮区域的因此一个字符串常量所占的存贮区域的字节数总比它的字符个数多一个字节。字节数总比它的字符个数多一个字节。C51中操作一个字符串常量的方法1)把字符串常量存放在一个字符数组之中,例如:chars=astring;数组s共有9个元素所组成,其中s8中的内容是0。实际上,在字符数组定义的过程中,编译程序直接把字符串复写到数组中,即对数组s初始化。2)用字符指针指向字符串,然后通过字符指针来访问字符串存贮区域。当字符串常量在表达式中出现时,根据数组的类型转换规则,它被转换成字符指针。因此,若我们定义了一字符指针cp:char*cp;于是可用:cp=astring;v使cp指向字符串常量中的第0号字符a,如图5-1-8所示。cpastring0图5-1-8指针指向字符串v以后我们可通过cp来访问这一存贮区域,如*cp或cp0就是字符a,而cpi或*(cp+i)就相当于字符串的第i号字符,但企图通过指针来修改字符串常量的行为是没有意义的。6.5.4指针数组v指针数组的定义格式为:类型标识类型标识*数组名数组名整型常量表达式整型常量表达式;例如:int*a10;v指针数组和一般数组一样,允许指针数组在定义时初始化。v指针数组的每个元素是指针变量,它只能存放地址。v所以对指向字符串的指针数组在说明赋初值时,是把存放字符串的首地址赋给指针数组的对应元素。例6-5-2打印1月至12月的月名。#include#includeinta34=1,3,5,7,9,11,13,15,17,19,21,23;char*month_name(intn)staticchar*name=Illegalmonth,January,February,March,April,May,June,July,August,September,October,November,December;return(n12)?name0:namen);main()inti;for(i=0;i13;i+)printf(%sn,month_name(i);getchar();程序运行后输出结果如图所示。6.5.5指针作为函数的形参v指针变量,既可以作为函数的形参,也可以作函数的实参。v指针变量作实参时,与普通变量一样,也是“值传递”,即将指针变量的值(一个地址)传递给被调用函数的形参(必须是一个指针变量)。v被调用函数不能改变实参指针变量的值,但可以改变实参指针变量所指向的变量的值。例6-5-3输入2个整数,按升序(从小到大排序)输出。要求实参为指针变量。#include#includevoidexchange(int*pointer1,int*pointer2)inttemp;temp=*pointer1,*pointer1=*pointer2,*pointer2=temp;voidmain(void)intnum1,num2;int*num1_p=&num1,*num2_p=&num2;/*定义并初始化指针变量num1_p和num2_p*/printf(nInputthefirstnumber:);scanf(%d,num1_p);printf(nInputthesecondnumber:);scanf(%d,num2_p);printf(nnum1=%d,num2=%d,num1,num2);/*输出num1和num2的初始值*/if(*num1_p*num2_p)/*num1_p*num2_p(即num1num2)*/exchange(num1_p,num2_p);/*指针变量作实参,调用exchange()函数*/printf(nmin=%d,max=%d,num1,num2);/*输出排序后的num1和num2的值*/while(1);程序运行输出结果如图结束语结束语谢谢大家聆听!谢谢大家聆听!64
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号