1、第第5章章 Cx51构造数据类型构造数据类型 5.1 数数 组组5.2 指指 针针5.3 结结 构构5.4 联联 合合5.5 枚枚 举举5.1 数数组组一维数组一维数组二维数组二维数组字符数组字符数组查查 表表数组与存储空间数组与存储空间这些按序排列的同类数据元素的集合称为这些按序排列的同类数据元素的集合称为数组数组。一个数组可以分解为多个数组元素,这些一个数组可以分解为多个数组元素,这些数组元素数组元素可以可以是是基本数据类型基本数据类型或是或是构造类型构造类型。因此按数组元素的类型不同,。因此按数组元素的类型不同,数组又可分为:数组又可分为:数值数组、数值数组、字符数组、字符数组、指针数组
2、、指针数组、结构数组等。结构数组等。一维数组一维数组1、一维数组的定义方式、一维数组的定义方式数组说明的一般形式为:数组说明的一般形式为:类型说明符类型说明符 存储类型存储类型 数组名数组名常量表达式常量表达式,;类型说明符类型说明符任一种基本数据类型或构造数据类型。任一种基本数据类型或构造数据类型。数数 组组 名名用户定义的数组标识符。用户定义的数组标识符。常量表达式常量表达式数据元素的个数,也称为数组的长度。数据元素的个数,也称为数组的长度。例如:例如:int data a10;说明整型数组说明整型数组a,有,有10个元素。个元素。float xdata b10,c20;说明实型数组说明实
3、型数组b,有,有10个元素,实型个元素,实型数组数组c,有,有20个元素。个元素。char data ch20;说明字符数组说明字符数组ch,有,有20个元素。个元素。对于数组类型说明应注意以下几点:对于数组类型说明应注意以下几点:1.数组的类型实际上是指数组元素的取值类型。对于同一个数组,其所有元数组的类型实际上是指数组元素的取值类型。对于同一个数组,其所有元素的数据类型都是相同的。素的数据类型都是相同的。2.数组名的书写规则应符合标识符的书写规定。数组名的书写规则应符合标识符的书写规定。3.数组名不能与其它变量名相同。数组名不能与其它变量名相同。4.方括号中常量表达式表示数组元素的个数,如
4、方括号中常量表达式表示数组元素的个数,如a5表示数组表示数组a有有5个元素。个元素。但是其下标从但是其下标从0开始计算。开始计算。因此因此5个元素分别为个元素分别为a0,a1,a2,a3,a4。5.不能在方括号中用变量来表示元素的个数不能在方括号中用变量来表示元素的个数,但是可以是符号常数或常量表但是可以是符号常数或常量表达式达式2、数组的初始化、数组的初始化初始化赋值的一般形式为:初始化赋值的一般形式为:类型说明符类型说明符 存储类型存储类型 数组名数组名常量表达式常量表达式=值,值值,值值值;(1)可以只给部分元素赋初值可以只给部分元素赋初值。当。当 中值的个数少于元素中值的个数少于元素个
5、数时,只给前面部分元素赋值。个数时,只给前面部分元素赋值。例如:例如:int a10=0,1,2,3,4;表示只给表示只给a0a45个元素赋值,而后个元素赋值,而后5个元素自动赋个元素自动赋0值。值。语言对数组的初始赋值有以下几点规定:语言对数组的初始赋值有以下几点规定:(2)只能给元素逐个赋值,不能给数组整体赋值。只能给元素逐个赋值,不能给数组整体赋值。例如:给十个元素全部赋例如:给十个元素全部赋1值,只能写为:值,只能写为:int a10=1,1,1,1,1,1,1,1,1,1;而不能写为:而不能写为:int a10=1;(3)不给可初始化的数组赋初值,则全部元素均为不给可初始化的数组赋初
6、值,则全部元素均为0值值。(4)如给全部元素赋值,则在数组说明中,如给全部元素赋值,则在数组说明中,可以不给出数组可以不给出数组元素的个数。元素的个数。例如:例如:int a5=1,2,3,4,5;可写为:可写为:int a=1,2,3,4,5;指向结构类型数据的指针enum _Time A1=1,B1=3,C1=7 data eTime;在Keil Cx51的头文件absacc.指向结构类型数据的指针1、指向数组的指针变量定义、引用和赋值因此5个元素分别为a0,a1,a2,a3,a4。p;time_of_day;(1)枚举表中,每一项符号代表一个整数值。unsigned long secs_
7、in_year;while(*xd_ptr)在Keil Cx51的头文件absacc.因此按数组元素的类型不同,数组又可分为:*(app+i)或*(a+i)则都表示数组元素ai,即数组a的第i个元素。#include absacc.#include absacc.在指针变量app未被初始化之前,它和数组a毫不相干,没有任何关系。语言允许用字符串的方式对数组作初始化赋值。struct msg1 *p;/定义指针二维数组二维数组二维数组说明的一般形式是:二维数组说明的一般形式是:类型说明符类型说明符 存储类型存储类型 数组名数组名常量表达式常量表达式1常量表达式常量表达式2;1、二维数组的定义方式
8、、二维数组的定义方式常量表达式常量表达式1第一维下标的长度,第一维下标的长度,常量表达式常量表达式2 第二维下标的长度第二维下标的长度 例如:例如:int a34;说明了一个三行四列的数组,数组名为说明了一个三行四列的数组,数组名为a,其下标变量的类,其下标变量的类型为整型。型为整型。2、数组的初始化、数组的初始化 二维数组初始化也是在类型说明时给各下标变量赋以二维数组初始化也是在类型说明时给各下标变量赋以初值。初值。二维数组可按行分段赋值,也可按行连续赋值。二维数组可按行分段赋值,也可按行连续赋值。例如:例如:数组数组a53(1)按行分段赋值)按行分段赋值int data a53=80,75
9、,92,61,65,71,59,63,70,85,87,90,76,77,85;for(i=0;istuff=stuff;int*b=p+;+p-flgif(io_status.当程序中设定了一个数组后,C编译器就会在系统的存储空间开辟一个区域用于存储该数组的内容。char sex;共用体经常被用来提供同一个数据的不同的表达方式。此行代码也在外部存储器的code区定义一个具有3行字符数为7的字符数组。struct birthday data;下面以二维数组为例来说明多维数组的指针和指针变量的使用方法(运行程序,编译)(1)枚举表中,每一项符号代表一个整数值。void rqsendmssage(
10、struct msg1 *m);p;例如:int a34;while(*xd_ptr)该操作还有跟使用环境有关:2、通过指针引用数组元素(2)按行连续赋值)按行连续赋值 int data a53=80,75,92,61,65,71,59,63,70,85,87,90,76,77,85;(3)可以只对部分元素赋初值,未赋初值的元素自动取)可以只对部分元素赋初值,未赋初值的元素自动取0值。值。例如:例如:int data a33=1,2 ,3 ;是对每一行的第一列元素赋值,未赋值的元素取是对每一行的第一列元素赋值,未赋值的元素取0值。值。赋值后各元素的值为:赋值后各元素的值为:1 0 0 2 0
11、0 3 0 0 int data a 33=0,1,0,0,2,3 ;赋值后的元素值为赋值后的元素值为 0 1 0 0 0 2 3 0 0 3、数组是一种构造类型的数据。、数组是一种构造类型的数据。二维数组可以看二维数组可以看作是由一维数组的嵌套而构成的。作是由一维数组的嵌套而构成的。例:例:二维数组二维数组a34,可分解为三个一维数组,其数组名分别为,可分解为三个一维数组,其数组名分别为a0,a1,a2。字符数组字符数组 用来存放字符量的数组称为字符数组。用来存放字符量的数组称为字符数组。字符数组类型字符数组类型说明的形式与前面介绍的数值数组相同。说明的形式与前面介绍的数值数组相同。1、字符
12、数组的定义方式、字符数组的定义方式字符数组类型说明的形式与前面介绍的数值数组相同。字符数组类型说明的形式与前面介绍的数值数组相同。例如:例如:char c10;2、字符数组的初始化、字符数组的初始化char c10=c,p,r,o,g,r,a,m;例如:例如:char c=c,p,r,o,g,r,a,m;可写为:可写为:char c=C program;或去掉或去掉 写为:写为:char c=C program;语言允许用字符串的方式对数组作初始化赋值。语言允许用字符串的方式对数组作初始化赋值。字符串总是以字符串总是以0作为串的结束符。因此当把一个字符作为串的结束符。因此当把一个字符串存入一个
13、数组时,串存入一个数组时,也把结束符也把结束符0存入数组,并以此作存入数组,并以此作为该字符串是否结束的标志。为该字符串是否结束的标志。用字符串方式赋值比用字符逐个赋值要多占一个字节,用字符串方式赋值比用字符逐个赋值要多占一个字节,用于存放字符串结束标志用于存放字符串结束标志0。3、2维字符数组定义及初始化维字符数组定义及初始化 此行代码在此行代码在RAM的的data区定义一个具有区定义一个具有3行字符数少行字符数少于于8的的字符数组。每一行的最后一个字节用于存放结束符字符数组。每一行的最后一个字节用于存放结束符NULL。char data strArray38=“happy!”,n,Stri
14、ng”,n,Hello!”,n;char data strArray38;对于包含初始化数据的多对于包含初始化数据的多维数组,第一个下标的具体数维数组,第一个下标的具体数字也可以省略:字也可以省略:此行代码也在此行代码也在外部存储器外部存储器的的code区定义一个区定义一个具有具有3行字符数为行字符数为7的的字符数组。每一行的最后一个字符数组。每一行的最后一个字节用于存放结束符字节用于存放结束符NULL。char code strArray8=happy!,String!,Hello!”;数组的一个非常有用的功能就是查表。数组的一个非常有用的功能就是查表。查表查表 特别是对那些对于传感器的非线
15、性转换需要进行补偿特别是对那些对于传感器的非线性转换需要进行补偿的场合,使用查表法(如果有必要再加上线性插值法)将的场合,使用查表法(如果有必要再加上线性插值法)将比采用复杂的曲线拟合所需要的数学运算要有效得多。比采用复杂的曲线拟合所需要的数学运算要有效得多。表格查找执行起来速度非常快,所用的代码也要少得表格查找执行起来速度非常快,所用的代码也要少得多,所用的表格可以事先计算好装入特殊的多,所用的表格可以事先计算好装入特殊的ROM区,或区,或者直接放在者直接放在code区,进一步使用插值还可以增加表的精区,进一步使用插值还可以增加表的精确度,减少表的长度。确度,减少表的长度。当程序中设定了一个
16、数组后,当程序中设定了一个数组后,C编译器就会编译器就会在系统的存储空间开辟一个区域用于存储该数组在系统的存储空间开辟一个区域用于存储该数组的内容。的内容。数组与存储空间数组与存储空间 对于字符数组而言,数据占据了存储器中一对于字符数组而言,数据占据了存储器中一串连续的字节位置。对于其它数组,如整形串连续的字节位置。对于其它数组,如整形(int)数组,将在存储区占据一串连续的双字节位置,数组,将在存储区占据一串连续的双字节位置,由此类推。由此类推。对于多维数组来说,一个对于多维数组来说,一个10 x10 x10的三的三维浮点数组需要大约维浮点数组需要大约4k的存储空间。一般情况的存储空间。一般
17、情况下数组存储空间不能大于下数组存储空间不能大于64k。5.2 指指 针针指针的基本慨念指针的基本慨念数组指针和指向数组的指针变量数组指针和指向数组的指针变量指向多维数组的指针和指针变量指向多维数组的指针和指针变量关于关于Keil Cx51的指针类型的指针类型指针的基本慨念指针的基本慨念 指针是一个包含存储区地址的变量,因为指针指针是一个包含存储区地址的变量,因为指针中包含了变量的地址,它可以对它所指向的变量进中包含了变量的地址,它可以对它所指向的变量进行寻址,就像在行寻址,就像在8051 data区中进行寄存器间接区中进行寄存器间接寻址,和在寻址,和在xdata区中用区中用DPTR进行寻址一
18、样。使进行寻址一样。使用指针是非常方便的,因为它很容易从一个变量移用指针是非常方便的,因为它很容易从一个变量移到下一个变量,所以可以写出对大量变量进行操作到下一个变量,所以可以写出对大量变量进行操作的通用程序。的通用程序。指针要定义类型说明,说明它指向何种类型的变量。指针要定义类型说明,说明它指向何种类型的变量。下面是一些指针定义的例子:下面是一些指针定义的例子:unsigned char*my_ptr,*anther_ptr;unsigned int*int_ptr;float*float_ptr;time_str*time_ptr;1、指针变量的定义、指针变量的定义类型识别符类型识别符 *
19、指针变量名指针变量名 假设你用关键字假设你用关键字long定义一个指针定义一个指针C,就把指针所指的地址看成一,就把指针所指的地址看成一个长整型变量的基址。个长整型变量的基址。这并不说明这个指针被强迫指向长整型的变量,而是说明这并不说明这个指针被强迫指向长整型的变量,而是说明C把该指把该指针所指的变量看成长整型的。针所指的变量看成长整型的。指针可被赋予任何已经定义的变量或存储器的地址:指针可被赋予任何已经定义的变量或存储器的地址:My_ptr=&char_val;Int_ptr=&int_array10;Time_str=&oldtime;2、指针变量的引用、指针变量的引用 可通过加减来移动指
20、针,指向不同的存储区地址;在可通过加减来移动指针,指向不同的存储区地址;在处理数组的时候,这一点特别有用,当处理数组的时候,这一点特别有用,当指针加指针加1的时候,的时候,它加上指针所指数据类型的长度它加上指针所指数据类型的长度:P107数组说明的一般形式为:#include absacc.因此当把一个字符串存入一个数组时,也把结束符0存入数组,并以此作为该字符串是否结束的标志。结构体变量名.请注意,它和(*p)+以及*(p+)都不相同。共用体变量中每个成员的引用方式与结构体变量完全相同,有以下三种形式:当用指针来引用结构或联合的成员时,可用如下方法:注:相同结构体类型的变量可以相互赋值。#i
21、nclude days=234;*time_ptr.hour=12;指针既可以指向变量,也可以指向数组。指针既可以指向变量,也可以指向数组。数组指针和指向数组的指针变量数组指针和指向数组的指针变量数组的指针数组的指针:数组的起始地址;:数组的起始地址;指向数组的指针变量指向数组的指针变量:用于存放数组起始位置的变量。:用于存放数组起始位置的变量。1、指向数组的指针变量定义、引用和赋值、指向数组的指针变量定义、引用和赋值首先定义一个数组和指向该类型数组的指针:首先定义一个数组和指向该类型数组的指针:int a10;/定义包含定义包含10个元素的整形数组个元素的整形数组int*app;/定义整形数
22、组的通用指针定义整形数组的通用指针 在指针变量在指针变量app未被初始化之前,它和数组未被初始化之前,它和数组a毫不相干,毫不相干,没有任何关系。没有任何关系。指针变量指针变量app可以初始化并使它指向数组可以初始化并使它指向数组a:经过初始化后数组经过初始化后数组a的第一个元素的第一个元素a0的地址值就赋的地址值就赋给了指针变量给了指针变量app,这种赋值是否改变指针变量的通用属,这种赋值是否改变指针变量的通用属性要看相关的数组而定,上述赋值并不改变指针变量的通性要看相关的数组而定,上述赋值并不改变指针变量的通用属性。用属性。app=a;/数组指针初始化数组指针初始化 经过下述指针赋值后会同
23、时改变指针变量的通用属性经过下述指针赋值后会同时改变指针变量的通用属性(改变为改变为data属性属性):int data a10;/data区定义整形数组区定义整形数组int*app;/定义整形数组的通用指针定义整形数组的通用指针app=a;/指针初始化指针初始化C语言规定数组名称可以代表数组的首地址,所以下面的两语言规定数组名称可以代表数组的首地址,所以下面的两个赋值方法是等同的:个赋值方法是等同的:app=&a0;/指针初始化指针初始化app=a;/指针初始化指针初始化也可以把指针变量的定义和赋值放在同一条语句中:也可以把指针变量的定义和赋值放在同一条语句中:int code a10;2、
24、通过指针引用数组元素、通过指针引用数组元素 引用数组元素可以利用数组下标获取引用数组元素可以利用数组下标获取ai,也可以利,也可以利用指针法获取用指针法获取appi。与数组下标法相比,使用指针法引用数组元素一般情与数组下标法相比,使用指针法引用数组元素一般情况下能够使目标程序代码效率高,占用内存少,运行速度况下能够使目标程序代码效率高,占用内存少,运行速度快。快。app+i或或a+i都是数组元素都是数组元素ai的地址,即它们都指向的地址,即它们都指向数组数组a的第的第i个元素;个元素;*(app+i)或或*(a+i)则都表示数组元素则都表示数组元素ai,即数组,即数组a的第的第i个元素。个元素
25、。需要特别注意:需要特别注意:C语言规定,语言规定,app+i或或a+i都是指向都是指向数组数组a的第的第i个元素,而不是指向其字节流的第个元素,而不是指向其字节流的第i个字节。个字节。例例 输出具有输出具有10个元素的整形数组的每个元素的值个元素的整形数组的每个元素的值解解1 下标法:下标法:main()int a10=1,2,3,4,5,6,7,8,9,10;unsigned char i;for(i=0;i10;i+)printf(%d,ai);解解2 通过数组名计算元素地址:通过数组名计算元素地址:main()int a10=1,2,3,4,5,6,7,8,9,10;unsigned
26、char i;for(i=0;i10;i+)printf(%d,*(a+i);解解3 通过指针变量计算元素地址:通过指针变量计算元素地址:main()int a10=1,2,3,4,5,6,7,8,9,10;int*p;for(p=a;pa+10;p+)printf(%d,*p);赋值后的元素值为 0 1 0 0 0 2 3 0 0语言允许用字符串的方式对数组作初始化赋值。for(p=a;pstuff=stuff;请注意,它和(*p)+以及*(p+)都不相同。3.关于指针变量的运算关于指针变量的运算对于数组对于数组a10和同类型指针变量和同类型指针变量p=a:p+(或或p+=1)该操作将使指针
27、变量该操作将使指针变量p指向下一个元素,即指向下一个元素,即a1,若再执行,若再执行x=*p则将取出元素则将取出元素a1赋值给赋值给x。该操作还有跟使用环境有关:该操作还有跟使用环境有关:int*b=p+;则表示先把指针则表示先把指针p的当前值赋给指针变量的当前值赋给指针变量b,然后指针变量然后指针变量p指向下一个元素。指向下一个元素。*p+由于运算符由于运算符+和和*的优先级别相同,而结合方的优先级别相同,而结合方向对向对p来说来说自左向右自左向右,所以该运算先执行,所以该运算先执行*p,然,然后再执行后再执行p+。其作用是先得到指针变量其作用是先得到指针变量p指向的值即指向的值即*p,然,
28、然后再执行后再执行p的自加运算。假如没有使用环境,仅的自加运算。假如没有使用环境,仅仅是执行仅是执行p的自加运算,等效于的自加运算,等效于p+;假如存在使;假如存在使用环境:用环境:int b=*p+;则相当于两条语句:则相当于两条语句:int b=*p;p+;请注意,它和请注意,它和(*p)+以及以及*(p+)都不相同。都不相同。区别:区别:n(*p)+nP指向的元素的内容自指向的元素的内容自+1n*(p+)n先执行()先执行()-P指向指向的元素自的元素自+1,即下一,即下一个元素个元素*p+与与*+p不同不同 前者在使用前者在使用p后进行后进行p的的自加,而后者则是在自加,而后者则是在使
29、用使用p前就进行前就进行p的自加:的自加:int a10;int*p=a;分别执行下列语句:分别执行下列语句:int b=*p+;int c=*+p;前者得到的前者得到的b为为a0,而后者得到的,而后者得到的c为为a1,p在两种运算中最后的结果相同,都指向第二个元在两种运算中最后的结果相同,都指向第二个元素素a1。(*p)+作用是对指针变量作用是对指针变量p所指向的元素值即所指向的元素值即*p执行执行自加运算,结果不影响指针自加运算,结果不影响指针p,但是影响,但是影响p所指的所指的第一个数组元素的值。第一个数组元素的值。P108,4 若若p指向数组元素中第指向数组元素中第i个元素:个元素:P
30、108,5*(p-)与)与ai-等价;等价;*(+p)与与a+i等价;等价;*(-p)与与a-i等价;等价;所有这些运算都和运算环境有关。所有这些运算都和运算环境有关。经过初始化后数组a的第一个元素a0的地址值就赋给了指针变量app,这种赋值是否改变指针变量的通用属性要看相关的数组而定,上述赋值并不改变指针变量的通用属性。int day;struct time_str time;struct person mytime;可通过加减来移动指针,指向不同的存储区地址;一个使用结构指针的简单例子:因此当把一个字符串存入一个数组时,也把结束符0存入数组,并以此作为该字符串是否结束的标志。struct
31、personstruct 结构体类型名该操作将使指针变量p指向下一个元素,即a1,若再执行x=*p则将取出元素a1赋值给x。time_str*time_ptr;struct birthday例如:一个长整型变量用来存放四个寄存器的值,如果希望对这些数据有两种表达方法,可以在联合中定义一个长整型变量,同时再定义一个字节数组:例如:char c10;int*app;/定义整形数组的通用指针char address100;1、基于存储器的指针p110char sex;2、通过指针引用数组元素 下面以二维数组为例来说明多维数组的指针和指针变量下面以二维数组为例来说明多维数组的指针和指针变量的使用方法的
32、使用方法(运行程序,编译运行程序,编译)指向多维数组的指针和指针变量指向多维数组的指针和指针变量main()int a34=1,3,5,7,9,11,13,15,17,19,21,23 int(*p)4,i,j;p=a;i =2;j =2;printf(a%d.%d =%dn,i,j,*(*(p+i)+j);/书上书上(P.110)括号位置有问题括号位置有问题运算结果:运算结果:a2,2=21 这里实际上出现了这里实际上出现了指针的指针指针的指针的问题,可以:的问题,可以:int a34=1,3,5,7,9,11,13,15,17,17,19,21,23int(*p)4=a;定义指针变量定义指
33、针变量int(*p)4的含义:的含义:p是一组指针变量是一组指针变量(共共4个个元素元素)的第一个指针变量的地址,这里数组元素是指针变量。的第一个指针变量的地址,这里数组元素是指针变量。假如指针变量元素的个数不确定,就可以定义成指针的指针假如指针变量元素的个数不确定,就可以定义成指针的指针int*p。p=a指向数组指向数组a的第一个数组元素的地址后(的第一个数组元素的地址后(这里数组名这里数组名a可可以看做以看做a4数组的首地址数组的首地址p109):):p+1和和a+1等价指向数组等价指向数组a的第的第1行首元素地址;行首元素地址;p+2和和a+2等价指向数组等价指向数组a的第的第2行首元素
34、地址;行首元素地址;:*(p+1)+3和和&a13等价指向等价指向a13的地址;的地址;*(*(p+1)+3)和和a13等价标示等价标示a13的值。的值。习题习题p.1231 1、2 2、9 9、1010Keil Cx51支持支持“基于存储器基于存储器”的具体指针的具体指针和和通用通用(一般一般)指针指针。关于关于Keil Cx51的指针类型的指针类型1、基于存储器的指针基于存储器的指针p110 基于存储器的指针就是基于存储器的指针就是在在 指针的声明中包含一个存储指针的声明中包含一个存储类型标识符,指向一个确定的存储区,这种指针叫类型标识符,指向一个确定的存储区,这种指针叫具体指具体指针针。
35、例如:例如:char data*str;/*ptr to string in data*/int xdata*numtab;/*ptr to int(s)in xdata*/long code*powtab;/*ptr to long(s)in code*/基于存储区指针只用一个字节基于存储区指针只用一个字节idata data bdata 和和pdata 指针或两字节指针或两字节code 和和xdata 指针。指针。基于存储区指针保存存储区的指定。基于存储区指针保存存储区的指定。在指针声明前加一个存储类型标识符。在指针声明前加一个存储类型标识符。例如:例如:char data*xdata s
36、tr;/*ptr in xdata to data char*/int xdata*data numtab;/*ptr in data to xdata int*/long code*idata powtab;/*ptr in idata to code long*/2、通用通用(一般一般)指针指针 Cx51提供一个提供一个3字节的字节的通用存储器指针通用存储器指针,通用指针的头,通用指针的头一个字节表明指针所指的存储区空间,另外两个字节存储一个字节表明指针所指的存储区空间,另外两个字节存储16位偏移量。对于位偏移量。对于data、idata和和pdata段,只需要段,只需要8位偏移。位偏移。
37、P111-112通用指针和标准通用指针和标准C 指针的声明相同。指针的声明相同。例如:例如:char *s;/*string ptr*/int *numptr;/*int ptr*/通用指针可访问通用指针可访问8051 存储空间内的任何变量。存储空间内的任何变量。基于存储器的指针基于存储器的指针其类型由其类型由C代码中相关的代码中相关的存储器类型决定,并在编译时确定,存储器类型决定,并在编译时确定,用这种指针用这种指针可以非常高效地访问相关的存储器。可以非常高效地访问相关的存储器。通用指针包含一个字节的类型描述字节,使通用指针包含一个字节的类型描述字节,使用时要考虑类型字节,并根据类型字节的内
38、容进用时要考虑类型字节,并根据类型字节的内容进行不同的处理,所以对相关存储器的访问效率会行不同的处理,所以对相关存储器的访问效率会降低。降低。指针类型指针类型描述描述大小大小通用指针通用指针3字节字节xdata指针指针2字节字节code指针指针2字节字节idata指针指针1字节字节data指针指针1字节字节pdata指针指针1字节字节各种类型指针变量的字节数如下表所示:各种类型指针变量的字节数如下表所示:地址偏移地址偏移+0+1+2内容内容存储器类型存储器类型偏移量高位偏移量高位偏移量低位偏移量低位通用指针通用指针3个字节的含义:个字节的含义:第一个字节表明具体存储器的类型第一个字节表明具体存
39、储器的类型:类型类型idata/data/bdataxdatapdatacode值值0 x000 x010 xFE0 xFF地址偏移地址偏移+0+1+2内容内容0 x010 x120 x34 其它类型值可能会导致不可预测的程序动作,具体类型其它类型值可能会导致不可预测的程序动作,具体类型值还和编译器的版本有关。以值还和编译器的版本有关。以xdata类型的类型的0 x1234地址地址为指针可以表示如下:为指针可以表示如下:在在Keil Cx51的头文件的头文件absacc.h,使用这个头文件,可利,使用这个头文件,可利用三字节通用指针作为抽象指针,为个存储器空间提供绝对用三字节通用指针作为抽象指
40、针,为个存储器空间提供绝对地址存取技术。地址存取技术。对于具体指针的定义,可以使用下面任何一种方式:对于具体指针的定义,可以使用下面任何一种方式:char data*xd_ptr;data char*xd_ptr;其中第一种方式比较标准。其中第一种方式比较标准。pdata 指针或两字节code 和xdata 指针。/书上(P.一个使用结构指针的简单例子:(1)枚举表中,每一项符号代表一个整数值。struct birthday data;对于包含初始化数据的多维数组,第一个下标的具体数字也可以省略:其中第一种方式比较标准。union time_typeint month;char address
41、100;每一行的最后一个字节用于存放结束符NULL。共用体中的成员可以是简单变量,也可以是数组、指针、结构体和共用体。unsigned int days;struct birthday data;struct person p;unsigned char*my_ptr,*anther_ptr;struct person p1,p2;time_ptr=oldtime_ptr;/两个指针指向同一地址int *numptr;/*int ptr*/#include char*generic_ptr,mystring=Test output;char data*xd_ptr;下面的例子反映出使用具体指针
42、比使用通用指针更加下面的例子反映出使用具体指针比使用通用指针更加高效,使用通用指针的第一个循环需要高效,使用通用指针的第一个循环需要378个处理周期,个处理周期,使用具体指针只需要使用具体指针只需要151个处理周期:个处理周期:void main()generic_ptr=mystring;while(*generic_ptr)XBYTE0 x0000=*generic_ptr;generic_ptr+;xd_ptr=mystring;while(*xd_ptr)XBYTE0 x0000=*xd_ptr;xd_ptr+;由于使用具体指针能够节省不少时间,所以由于使用具体指针能够节省不少时间,所
43、以我们一般都不使用通用指针。我们一般都不使用通用指针。当你在程序中使用指针时,你应指定指针的当你在程序中使用指针时,你应指定指针的类型,确定它们指向哪个区域,如类型,确定它们指向哪个区域,如xdata或或code区,这样你的代码会更加紧凑,因为区,这样你的代码会更加紧凑,因为编译器编译器不必去确定指针所指向的存储区,不必去确定指针所指向的存储区,因为你已经进因为你已经进行了说明。行了说明。5.3 结结 构构结构的定义和引用结构的定义和引用结构数组结构数组指向结构类型数据的指针指向结构类型数据的指针结构的定义和引用 结构是一种定义类型,它允许程序员把一系结构是一种定义类型,它允许程序员把一系列变
44、量集中到一个单元中,当某些变量相关的时列变量集中到一个单元中,当某些变量相关的时候,使用这种类型是很方便的。候,使用这种类型是很方便的。例如,用一系列变量来描述一天的时间。例如,用一系列变量来描述一天的时间。定义时、分、秒三个变量:定义时、分、秒三个变量:unsighed char hour,min,sec;定义一个天的变量:定义一个天的变量:unsighed int days;通过使用结构可以把这四个变量定义在一起,给他们通过使用结构可以把这四个变量定义在一起,给他们一个共同的名字。声明结构的语法如下:一个共同的名字。声明结构的语法如下:struct time_str unsigned ch
45、ar hour,min,sec;unsigned int days;time_of_day;这告诉编译器定义一个这告诉编译器定义一个类型名类型名为为time_str的结构,并的结构,并定义一个定义一个名为名为time_of_day的结构变量。的结构变量。1、结构体类型定义struct 结构体类型名结构体类型名 类型名类型名 结构体成员名;结构体成员名;/*成员表成员表*/;例例1描述通讯录的结构体类型。描述通讯录的结构体类型。struct person char name20;int age;char sex;char address100;long zipcode;例例2.结构体类型的结构体
46、类型的嵌套定义。嵌套定义。struct birthday int year;int month;int day;struct person char name20;struct birthday date;char sex;char address100;long zipcode;2、定义结构类型变量(1)间接定义先定义结构类型,后定义类型变量。)间接定义先定义结构类型,后定义类型变量。struct 结构体类型名结构体类型名 成员表;成员表;;struct 结构体类型名结构体类型名 变量名表;变量名表;struct birthday int year;int month;int day;str
47、uct person char name20;struct birthday date;char sex;char address100;long zipcode;struct person p;(2)在定义结构类型的同时定义该类型的变量。)在定义结构类型的同时定义该类型的变量。struct 结构体类型名结构体类型名 成员表;成员表;结构体变量名表结构体变量名表;struct birthday int year;int month;int day;struct person char name20;struct birthday data;char sex;char address100;lo
48、ng zipcode;p;(3)直接定义结构变量,没有结构名。)直接定义结构变量,没有结构名。struct 成员表;成员表;结构体变量名表结构体变量名表;struct birthday int year;int month;int day;struct char name20;struct birthday data;char sex;char address100;long zipcode;p;3、结构类型变量的引用 结构体一般不能作为一个整体参加数据处理,而参结构体一般不能作为一个整体参加数据处理,而参加各种运算和操作的是结构体的各个成员项数据。对成加各种运算和操作的是结构体的各个成员项数
49、据。对成员的使用方式:员的使用方式:结构体变量名结构体变量名.成员名成员名注:相同结构体类型的变量可以相互赋值。注:相同结构体类型的变量可以相互赋值。struct person p1,p2;p1=p2;p-cmd=0;enum 枚举名 变量列表;union time_typechar address100;一个使用结构指针的简单例子:数组名不能与其它变量名相同。p-nod=0;在指针声明前加一个存储类型标识符。需要特别注意:C语言规定,app+i或a+i都是指向数组a的第i个元素,而不是指向其字节流的第i个字节。关于Keil Cx51的指针类型 char name20;指针变量app可以初始化
50、并使它指向数组a:共用体变量的定义和结构体变量相似,可以先说明共用体类型,再定义变量,也可以在类型说明的同时定义变量。例如:一个长整型变量用来存放四个寄存器的值,如果希望对这些数据有两种表达方法,可以在联合中定义一个长整型变量,同时再定义一个字节数组:例如:char c10;类型名 结构体成员名;char code strArray8=Keil Cx51支持“基于存储器”的具体指针和通用(一般)指针。在在Keil C和大多数和大多数C编译器中,结构被提供了连续的编译器中,结构被提供了连续的存储空间,寻址空间内的变量顺序和定义时的变量顺序一存储空间,寻址空间内的变量顺序和定义时的变量顺序一样:样
侵权处理QQ:3464097650--上传资料QQ:3464097650
【声明】本站为“文档C2C交易模式”,即用户上传的文档直接卖给(下载)用户,本站只是网络空间服务平台,本站所有原创文档下载所得归上传人所有,如您发现上传作品侵犯了您的版权,请立刻联系我们并提供证据,我们将在3个工作日内予以改正。