单片机C语言开发技术.ppt_第1页
单片机C语言开发技术.ppt_第2页
单片机C语言开发技术.ppt_第3页
单片机C语言开发技术.ppt_第4页
单片机C语言开发技术.ppt_第5页
已阅读5页,还剩58页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

单片机C语言开发技术,第六章 数组与指针,内容概述,数组是一种构造类型的数据,通常用来处理具有相同属性的一批数据。本章主要介绍一维数组、二维数组、多维数组以及字符数组的定义、初始化、引用及应用。,C51语言还提供了构造类型的数据,它们有:数组类型、结构体类型、共用体类型。构造类型数据是由基本类型数据按一定规则组成的,因此有的书称它们为“导出类型”。,6.1 一维数组,6.1.1 一维数组的定义 一维数组的定义方式为: 类型说明符 数组名常量表达式; 例如: int a10; 它表示数组名为a,此数组有10个元素。,说明: 1) 数组名的定名规则和变量名相同,遵循标识符定名规则; 2) 数组名后是用方括弧括起来的常量表达式,不能用圆括弧,下面用法不对:int a(10); 3) 常量表达式表示元素的个数,即数组长度。例如,在a10中,10表示a数组有10个元素,下标从0开始,这10个元素是,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9。注意不能使用数组元素a10; (4) 常量表达式中可以包括常量和符号常量,不能包含变量。也就是说,C51不允许对数组的大小作动态定义,即数组的大小不依赖于程序运行过程中变量的值。,例如,下面这样定义数组是不行的: int n; scanf(“%d“,,6.1.2 一维数组元素的引用,数组必须先定义,后使用。C51语言规定只能逐个引用数组元素而不能一次引用整个数组。 数组元素的表示形式为: 数组名下标 下标可以是整型常量或整型表达式。例如: a0=a5+a7-a2*3,例6-1-1 数组元素的引用,#include #includer void main(void ) int i,a10; #ifndef MONITOR51 /* 需要串口输出时请作如下设置*/ SCON = 0x50; /* 方式 1, 允许接收 */ TMOD |= 0x20; /* TMOD:定时器1方式2 */ TH1 = 221; /* 1200bps 16MHz */ TR1 = 1; /* 启动定时器1 */ TI = 1; /*Keil C自带的puchar()函数需要设置TI1*/ #endif for (i=0; i=0; i-) printf(“%d “,ai); ,6.1.3 一维数组的初始化,对数组元素的初始化可以用以下方法实现: 1)在定义数组时对数组元素赋以初值。 例如: int a10=0,1,2,3,4,5,6,7,8,9; 2) 可以只给一部分元素赋值。 例如: int a10=0,1,2,3,4; 定义a数组有10个元素,但花括弧内只提供5个初值,这表示只给前面5个元素赋初值,后5个元素值为0。,3) 如果想使一个数组中全部元素值为0,可以写成 int a10=0,0,0,0,0,0,0,0,0,0; 不能写成 int a10=0*10; 4) 在对全部数组元素赋初值时,可以不指定数组长度。例如: int a5=1,2,3,4,5; 可以写成 int a=1,2,3,4,5,6.1.4 一维数组应用举例,例6-1-2 已知某课程的平时、实习、测验和期末成绩,求该课程的总评成绩。其中平时、实习、测验和期末分别占10、20、20、50。 #include #include void main(void) int i=1,j; char con_key=x20; / x20 空格键的ASCII码 float score5,ratio4=0.1,0.2,0.2,0.5; /*定义成绩、比例系数数组*/ #ifndef MONITOR51 /* 需要从串口1输出时请作如下设置*/ SCON = 0x50; /* 方式 1, 允许接收 */ TMOD |= 0x20; /* TMOD:定时器1方式2 */ TH1 = 221; /* 1200bps 16MHz */ TR1 = 1; /* 启动定时器1 */ TI = 1; /*Keil C自带的puchar()函数需要设置TI1*/ #endif,while(con_key=x20) printf(“输入第%2d个学生的成绩n“, i+); printf(“平时 实习 测验 期末成绩n“); score4=0; /* score4:存储总评成绩*/ for(j=0; j4; j+) scanf(“%f“, ,6.2 二维数组,6.2.1 二维数组的定义 二维数组定义的一般形式为 类型说明符 数组名常量表达式常量表达式 例如: float a34,b510; 不能写成 float a3,4,b5,10;,6.2.2二维数组元素的引用,引用二2维数组元素的形式为: 数组名行下标表达式列下标表达式 1 “行下标表达式”和“列下标表达式”,都应是整型表达式或符号常量。 2 “行下标表达式”和“列下标表达式”的值,都应在已定义数组大小的范围内。假设有数组x34,则可用的行下标范围为02,列下标范围为03。 3 对基本数据类型的变量所能进行的操作,也都适合于相同数据类型的二维数组元素。,6.2.3 二维数组的初始化,1 按行赋初值 数据类型 数组名行常量表达式列常量表达式第0行初值表,第1行初值表,最后1行初值表; 赋值规则:将”第0行初值表”中的数据,依次赋给第0行中各元素;将“第1行初值表”中的数据,依次赋给第1行各元素;以此类推。 2 按二维数组在内存中的排列顺序给各元素赋初值 数据类型 数组名行常量表达式列常量表达式初值表; 赋值规则:按二维数组在内存中的排列顺序,将初值表中的数据,依次赋给各元素。 如果对全部元素都赋初值,则“行数”可以省略。 注意:只能省略“行数”。,6.2.4 二维数组应用举例,例6-2-1 有M个学生,学习N门课程,已知所有学生的各科成绩,编程:分别求每个学生的平均成绩和每门课程的平均成绩。,#define NUM_std 5 /*定义符号常量人数为5*/ #define NUM_course 4 /*定义符号常量课程为4*/ #include main() int i,j; static xdata float scoreNUM_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字符数组,用来存放字符量的数组称为字符数组。 字符数组类型说明的形式与前面介绍的数值数组相同。 例如: char c10; char c510;/即为二维字符数组。字符数组也允许在类型说明时作初始化赋值。 static char c=c, ,p,r,o,g,r,a,m;/ 当对全体元素赋初值时也可以省去长度说明,例6-3-1 定义一个二维数组,在放字符串“BASIC”、“DBASE”,并输出。 #include void main(void) int i,j; char a5=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“); ,字符串在语言中没有专门的字符串变量, 通常用一个字符数组来存放一个字符串。 字符串总是以0作为串的结束符。因此当把一个字符串存入一个数组时, 也把结束符0存入数组,并以此作为该字符串是否结束的标志。 有了0标志后,就不必再用字符数组的长度来判断字符串的长度了。,C51语言允许用字符串的方式对数组作初始化赋值。例如: static char c=c, ,p,r,o,g,r,a,m; 可写为: static char c=“C program“; 或去掉写为: sratic char c=“C program“; 用字符串方式赋值比用字符逐个赋值要多占一个字节, 用于存放字符串结束标志0。,除了上述用字符串赋初值的办法外,还可用printf函数和scanf函数一次性输出输入一个字符数组中的字符串, 而不必使用循环语句逐个地输入输出每个字符。 void main() static char c=“BASICndBASE“; printf(“%sn“,c); 注意在本例的printf函数中,使用的格式字符串为“%s”, 表示输出的是一个字符串。而在输出表列中给出数组名则可。 不能写为: printf(“%s“,c);,6.4 多维数组,多维数组的一般说明格式是: 类型 数组名第n维长度第n-1维长度第1维长度; 例如: int m32; /*定义一个整数型的二维数组*/ char c223; /*定义一个字符型的三维数组*/,数组m32共有3*2=6个元素, 顺序为: m00, m01, m10, m11, m20, m21; 数组c223共有2*2*3=12个元素, 顺序为: c000, c001, c002, c010, c011, c012, c100, c101, c102, c110, c111, c112, 数组占用的内存空间(即字节数)的计算式为: 字节数=第1维长度*第2维长度*.*第n维长度*该数组数据类型占用的字节数,C51中数组进行初始化有下述规则: 1) 数组的每一行初始化赋值用“”并用“,”分开, 总的再加一对“”括起来, 最后以“;“表示结束。 2) 多维数组存储是连续的, 因此可以用一维数组初始化的办法来初始化多维数组。 3) 对数组初始化时, 如果初值表中的数据个数比数组元素少, 则不足的数组元素用0来填补。,6.5 指针,6.51 指针和地址 6.5.1.1 指针变量的定义 C51语言中, 对于变量的访问形式之一, 就是先求出变量的地址, 然后再通过地址对它进行访问, 这就是这里所要论述的指针及其指针变量。 所谓变量的指针, 实际上指变量的地址 变量的地址虽然在形式上好象类似于整数, 但在概念上不同于以前介绍过的整数, 它属于一种新的数据类型, 即指针类型。 C51中, 一般用“指针”来指明这样一个表达式&x的类型, 而用“地址”作为它的值, 也就是说, 若x为一整型变量, 则表达式&x的类型是指向整数的指针, 而它的值是变量x的地址。,同样, 若 double d;则&d的类型是指向双精度数d的指针, 而&d的值是双精度变量d的地址。所以, 指针和地址是用来叙述一个对象的两个方面。 &x、&d的类型是不同的, 一个是指向整型变量x的指针,而另一个则是指向双精度变量d的指针。,指针变量的一般定义为: 类型标识符 *标识符; 其中标识符是指针变量的名字, 标识符前加了“*”号, 表示该变量是指针变量 “类型标识符”表示该指针变量所指向的变量的类型。 一个指针变量只能指向同一种类型的变量,定义一个指针类型的变量。 int *ip; 首先说明了它是一指针类型的变量, 注意在定义中不要漏写符号“*”, 否则它为一般的整型变量了。 另外, 在定义中的int 表示该指针变量为指向整型数的指针类型的变量, 有时也可称ip为指向整数的指针。 ip是一个变量, 它专门存放整型变量的地址。,指针变量在定义中允许带初始化项。如: int i, *ip= 。C51中规定, 当指针值为零时, 指针不指向任何有效数据, 有时也称指针为空指,6.5.1.2 指针变量的引用,既然在指针变量中只能存放地址, 因此, 在使用中不要将一个整数赋给一指针变量. 下面的赋值是不合法的: int *ip; ip=100;,假设: int i=200, x; int *ip; 可以把i的地址赋给ip: ip= 此时指针变量ip指向整型变量i, 假设变量i的地址为1800, 这个赋值可形象理解为下图所示的联系。,ip i 1800 200 图5-1-1 给指针变量赋值,以后我们便可以通过指针变量ip间接访问变量i, 例如: x=*ip; 运算符*访问以ip为地址的存贮区域, 而ip中存放的是变量i的地址, 因此, *ip访问的是地址为1800的存贮区域(因为是整数, 实际上是从1800开始的两个字节),它就是i所占用的存贮区域, 所以上面的赋值表达式等价于 x=i; 另外, 指针变量和一般变量一样, 存放在它们之中的值是可以改变的, 也就是说可以改变它们的指向, 假设 int i, j, *p1, *p2; i=a; j=b; p1=,则建立如图5-1-2所示的联系: p1 i a p2 i b 图5-1-2 赋值运算结果,这时赋值表达式: p2=p1; 就使p2与p1指向同一对象i, 此时*p2就等价于i, 而不是j, 图5-1-2就变成图5-1-3所示: p1 i a p2 j b 图5-1-3 p2=p1时的情形,如果执行如下表达式: *p2=*p1; 则表示把p1指向的内容赋给p2所指的区域, 此时图5-1-2就变成图5-1-4所示: p1 i a p2 j a 图5-1-4 *p2=*p1时的情形,由于指针是变量, 我们可以通过改变它们的指向, 以间接访问不同的变量, 这给程序员带来灵活性, 也使程序代码编写得更为简洁和有效。 指针变量可出现在表达式中, 设: int x, 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 指针和数组,指针和数组有着密切的关系, 任何能由数组下标完成的操作也都可用指针来实现, 但程序中使用指针可使代码更紧凑、更灵活。,6.5.2.1. 指向数组元素的指针,定义一个整型数组和一个指向整型的指针变量: int a10, *p; 和前面介绍过的方法相同, 可以使整型指针p指向数组中任何一个元素, 假定给出赋值运算 p= 根据地址运算规则, 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 二维数组元素的地址 为了说明问题, 我们定义以下二维数组: int a34=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所示 。,既然我们把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个元素所组成的数组指针,在C51中, 可定义如下的指针变量: int (*p)3; 指针p为指向一个由3个元素所组成的整型数组指针。 在定义中, 圆括号是不能少的, 否则它是指针数组。 这种数组的指针不同于前面介绍的整型指针, 当整型指针指向一个整型数组的元素时, 进行指针(地址)加1运算,表示指向数组的下一个元素, 此时地址值增加了2(因为放大因子为2), 而如上所定义的指向一个由3个元素组成的数组指针, 进行地址加1运算时, 其地址值增加了6(放大因子为23=6), 这种数组指针在C51中用得较少, 但在处理二维数组时, 还是很方便的。例如: int a34, (*p)4; p=a;,开始时p指向二维数组第0行, 当进行p+1运算时, 根据地址运算规则, 此时放大因子为42=8, 所以此时正好指向二维数组的第1行。 和二维数组元素地址计算的规则一样, *p+1指向a01, *(p+i)+j则指向数组元素aij。,例6-5-1 利用指针输出二维数组中的元素。,#include int a3 4= 1,3,5,7,9,11,13,15, 17,19,21,23 ; main() int i,(*b)4; b=a+1; /* b指向二维数组的第1行, 此时*b0或 *b是a10 */ for(i=1;i=4;b=b0+2,i+)/* 修改b的指向, 每次增加2 */ printf(“%d t“,*b0); printf(“ n“); for (i=0; i2; i+) b=a+i; /* 修改b的指向, 每次跳过二维数组的一行 */ printf(“%d t“,*(bi+1); printf (“ n“); ,程序运行结果如下:,6.5.3 字符指针,在程序中如出现字符串常量,C51编译程序就给字符串常量按排一存贮区域, 这个区域是静态的, 在整个程序运行的过程中始终占用。 字符串常量的长度是指该字符串的字符个数, 但在按排存贮区域时, C 编译程序还自动给该字符串序列的末尾加上一个空字符0, 用来标志字符串的结束。 因此一个字符串常量所占的存贮区域的字节数总比它的字符个数多一个字节。,C51中操作一个字符串常量的方法,1) 把字符串常量存放在一个字符数组之中, 例如: char s=“a string“; 数组s共有9个元素所组成, 其中s8中的内容是0。实际上, 在字符数组定义的过程中, 编译程序直接把字符串复写到数组中, 即对数组s初始化。 2) 用字符指针指向字符串, 然后通过字符指针来访问字符串存贮区域。当字符串常量在表达式中出现时, 根据数组的类型转换规则, 它被转换成字符指针。因此, 若我们定义了一字符指针cp: char *cp; 于是可用: cp=“a string“;,使cp指向字符串常量中的第0号字符a, 如图5-1-8所示。 cp a s t r

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论