第第5章章 Cx51构造数据类型构造数据类型 5.1 数数 组组5.2 指指 针针5.3 结结 构构5.4 联联 合合5.5 枚枚 举举5.1 数数组组一维数组一维数组二维数组二维数组字符数组字符数组查查 表表数组与存储空间数组与存储空间这些按序排列的同类数据元素的集合称为这些按序排列的同类数据元素的集合称为数组数组一个数组可以分解为多个数组元素,这些一个数组可以分解为多个数组元素,这些数组元素数组元素可以可以是是基本数据类型基本数据类型或是或是构造类型构造类型因此按数组元素的类型不同,因此按数组元素的类型不同,数组又可分为:数组又可分为:数值数组、数值数组、字符数组、字符数组、指针数组、指针数组、结构数组等结构数组等一维数组一维数组1、一维数组的定义方式、一维数组的定义方式数组说明的一般形式为:数组说明的一般形式为:类型说明符类型说明符 存储类型存储类型 数组名数组名常量表达式常量表达式,;类型说明符类型说明符任一种基本数据类型或构造数据类型任一种基本数据类型或构造数据类型数数 组组 名名用户定义的数组标识符用户定义的数组标识符常量表达式常量表达式数据元素的个数,也称为数组的长度数据元素的个数,也称为数组的长度。
例如:例如:int data a10;说明整型数组说明整型数组a,有,有10个元素float xdata b10,c20;说明实型数组说明实型数组b,有,有10个元素,实型个元素,实型数组数组c,有,有20个元素char data ch20;说明字符数组说明字符数组ch,有,有20个元素对于数组类型说明应注意以下几点:对于数组类型说明应注意以下几点:1.数组的类型实际上是指数组元素的取值类型对于同一个数组,其所有元数组的类型实际上是指数组元素的取值类型对于同一个数组,其所有元素的数据类型都是相同的素的数据类型都是相同的2.数组名的书写规则应符合标识符的书写规定数组名的书写规则应符合标识符的书写规定3.数组名不能与其它变量名相同数组名不能与其它变量名相同4.方括号中常量表达式表示数组元素的个数,如方括号中常量表达式表示数组元素的个数,如a5表示数组表示数组a有有5个元素但是其下标从但是其下标从0开始计算开始计算因此因此5个元素分别为个元素分别为a0,a1,a2,a3,a45.不能在方括号中用变量来表示元素的个数不能在方括号中用变量来表示元素的个数,但是可以是符号常数或常量表但是可以是符号常数或常量表达式达式2、数组的初始化、数组的初始化初始化赋值的一般形式为:初始化赋值的一般形式为:类型说明符类型说明符 存储类型存储类型 数组名数组名常量表达式常量表达式=值,值值,值值值;(1)可以只给部分元素赋初值可以只给部分元素赋初值。
当当 中值的个数少于元素中值的个数少于元素个数时,只给前面部分元素赋值个数时,只给前面部分元素赋值例如:例如: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)不给可初始化的数组赋初值,则全部元素均为不给可初始化的数组赋初值,则全部元素均为0值值4)如给全部元素赋值,则在数组说明中,如给全部元素赋值,则在数组说明中,可以不给出数组可以不给出数组元素的个数元素的个数例如:例如:int a5=1,2,3,4,5;可写为:可写为:int a=1,2,3,4,5;二维数组二维数组二维数组说明的一般形式是:二维数组说明的一般形式是:类型说明符类型说明符 存储类型存储类型 数组名数组名常量表达式常量表达式1常量表达式常量表达式2;1、二维数组的定义方式、二维数组的定义方式常量表达式常量表达式1第一维下标的长度,第一维下标的长度,常量表达式常量表达式2 第二维下标的长度第二维下标的长度 例如:例如:int a34;说明了一个三行四列的数组,数组名为说明了一个三行四列的数组,数组名为a,其下标变量的类,其下标变量的类型为整型。
型为整型2、数组的初始化、数组的初始化 二维数组初始化也是在类型说明时给各下标变量赋以二维数组初始化也是在类型说明时给各下标变量赋以初值二维数组可按行分段赋值,也可按行连续赋值二维数组可按行分段赋值,也可按行连续赋值例如:例如:数组数组a53(1)按行分段赋值)按行分段赋值int data a53=80,75,92,61,65,71,59,63,70,85,87,90,76,77,85;(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 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、字符数组的定义方式、字符数组的定义方式字符数组类型说明的形式与前面介绍的数值数组相同字符数组类型说明的形式与前面介绍的数值数组相同例如:例如: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作为串的结束符因此当把一个字符作为串的结束符因此当把一个字符串存入一个数组时,串存入一个数组时,也把结束符也把结束符0存入数组,并以此作存入数组,并以此作为该字符串是否结束的标志。
为该字符串是否结束的标志用字符串方式赋值比用字符逐个赋值要多占一个字节,用字符串方式赋值比用字符逐个赋值要多占一个字节,用于存放字符串结束标志用于存放字符串结束标志03、2维字符数组定义及初始化维字符数组定义及初始化 此行代码在此行代码在RAM的的data区定义一个具有区定义一个具有3行字符数少行字符数少于于8的的字符数组每一行的最后一个字节用于存放结束符字符数组每一行的最后一个字节用于存放结束符NULLchar data strArray38=“happy!”,n,String”,n,Hello!”,n;char data strArray38;对于包含初始化数据的多对于包含初始化数据的多维数组,第一个下标的具体数维数组,第一个下标的具体数字也可以省略:字也可以省略:此行代码也在此行代码也在外部存储器外部存储器的的code区定义一个区定义一个具有具有3行字符数为行字符数为7的的字符数组每一行的最后一个字符数组每一行的最后一个字节用于存放结束符字节用于存放结束符NULLchar code strArray8=happy!,String!,Hello!”;数组的一个非常有用的功能就是查表。
数组的一个非常有用的功能就是查表查表查表 特别是对那些对于传感器的非线性转换需要进行补偿特别是对那些对于传感器的非线性转换需要进行补偿的场合,使用查表法(如果有必要再加上线性插值法)将的场合,使用查表法(如果有必要再加上线性插值法)将比采用复杂的曲线拟合所需要的数学运算要有效得多比采用复杂的曲线拟合所需要的数学运算要有效得多表格查找执行起来速度非常快,所用的代码也要少得表格查找执行起来速度非常快,所用的代码也要少得多,所用的表格可以事先计算好装入特殊的多,所用的表格可以事先计算好装入特殊的ROM区,或区,或者直接放在者直接放在code区,进一步使用插值还可以增加表的精区,进一步使用插值还可以增加表的精确度,减少表的长度确度,减少表的长度当程序中设定了一个数组后,当程序中设定了一个数组后,C编译器就会编译器就会在系统的存储空间开辟一个区域用于存储该数组在系统的存储空间开辟一个区域用于存储该数组的内容数组与存储空间数组与存储空间 对于字符数组而言,数据占据了存储器中一对于字符数组而言,数据占据了存储器中一串连续的字节位置对于其它数组,如整形串连续的字节位置对于其它数组,如整形(int)数组,将在存储区占据一串连续的双字节位置,数组,将在存储区占据一串连续的双字节位置,由此类推。
由此类推对于多维数组来说,一个对于多维数组来说,一个10 x10 x10的三的三维浮点数组需要大约维浮点数组需要大约4k的存储空间一般情况的存储空间一般情况下数组存储空间不能大于下数组存储空间不能大于64k5.2 指指 针针指针的基本慨念指针的基本慨念数组指针和指向数组的指针变量数组指针和指向数组的指针变量指向多维数组的指针和指针变量指向多维数组的指针和指针变量关于关于Keil Cx51的指针类型的指针类型指针的基本慨念指针的基本慨念 指针是一个包含存储区地址的变量,因为指针指针是一个包含存储区地址的变量,因为指针中包含了变量的地址,它可以对它所指向的变量进中包含了变量的地址,它可以对它所指向的变量进行寻址,就像在行寻址,就像在8051 data区中进行寄存器间接区中进行寄存器间接寻址,和在寻址,和在xdata区中用区中用DPTR进行寻址一样使进行寻址一样使用指针是非常方便的,因为它很容易从一个变量移用指针是非常方便的,因为它很容易从一个变量移到下一个变量,所以可以写出对大量变量进行操作到下一个变量,所以可以写出对大量变量进行操作的通用程序的通用程序指针要定义类型说明,说明它指向何种类型的变量。
指针要定义类型说明,说明它指向何种类型的变量下面是一些指针定义的例子:下面是一些指针定义的例子:unsigned char*my_ptr,*anther_ptr;unsigned int*int_ptr;float*float_ptr;time_str*time_ptr;1、指针变量的定义、指针变量的定义类型识别符类型识别符 *指针变量名指针变量名 假设你用关键字假设你用关键字long定义一个指针定义一个指针C,就把指针所指的地址看成一,就把指针所指的地址看成一个长整型变量的基址个长整型变量的基址这并不说明这个指针被强迫指向长整型的变量,而是说明这并不说明这个指针被强迫指向长整型的变量,而是说明C把该指把该指针所指的变量看成长整型的针所指的变量看成长整型的指针可被赋予任何已经定义的变量或存储器的地址:指针可被赋予任何已经定义的变量或存储器的地址:My_ptr=&char_val;Int_ptr=&int_array10;Time_str=&oldtime;2、指针变量的引用、指针变量的引用 可通过加减来移动指针,指向不同的存储区地址;在可通过加减来移动指针,指向不同的存储区地址;在处理数组的时候,这一点特别有用,当处理数组的时候,这一点特别有用,当指针加指针加1的时候,的时候,它加上指针所指数据类型的长度它加上指针所指数据类型的长度:P107 指针间可像其它变量那样互相赋值,指针所指向的数据指针间可像其它变量那样互相赋值,指针所指向的数据也可通过引用指针来赋值:也可通过引用指针来赋值:time_ptr=oldtime_ptr;/两个指针指向同一地址两个指针指向同一地址*int_ptr=0 x4500;/把把0 x4500赋给赋给/int_ptr所指的变量所指的变量当用指针来引用结构或联合的成员时,可用如下方法:当用指针来引用结构或联合的成员时,可用如下方法:time_ptr-days=234;*time_ptr.hour=12;指针既可以指向变量,也可以指向数组。
指针既可以指向变量,也可以指向数组数组指针和指向数组的指针变量数组指针和指向数组的指针变量数组的指针数组的指针:数组的起始地址;:数组的起始地址;指向数组的指针变量指向数组的指针变量:用于存放数组起始位置的变量用于存放数组起始位置的变量1、指向数组的指针变量定义、引用和赋值、指向数组的指针变量定义、引用和赋值首先定义一个数组和指向该类型数组的指针:首先定义一个数组和指向该类型数组的指针:int a10;/定义包含定义包含10个元素的整形数组个元素的整形数组int*app;/定义整形数组的通用指针定义整形数组的通用指针 在指针变量在指针变量app未被初始化之前,它和数组未被初始化之前,它和数组a毫不相干,毫不相干,没有任何关系没有任何关系指针变量指针变量app可以初始化并使它指向数组可以初始化并使它指向数组a:经过初始化后数组经过初始化后数组a的第一个元素的第一个元素a0的地址值就赋的地址值就赋给了指针变量给了指针变量app,这种赋值是否改变指针变量的通用属,这种赋值是否改变指针变量的通用属性要看相关的数组而定,上述赋值并不改变指针变量的通性要看相关的数组而定,上述赋值并不改变指针变量的通用属性。
用属性app=a;/数组指针初始化数组指针初始化 经过下述指针赋值后会同时改变指针变量的通用属性经过下述指针赋值后会同时改变指针变量的通用属性(改变为改变为data属性属性):int data a10;/data区定义整形数组区定义整形数组int*app;/定义整形数组的通用指针定义整形数组的通用指针app=a;/指针初始化指针初始化C语言规定数组名称可以代表数组的首地址,所以下面的两语言规定数组名称可以代表数组的首地址,所以下面的两个赋值方法是等同的:个赋值方法是等同的:app=&a0;/指针初始化指针初始化app=a;/指针初始化指针初始化也可以把指针变量的定义和赋值放在同一条语句中:也可以把指针变量的定义和赋值放在同一条语句中:int code a10;2、通过指针引用数组元素、通过指针引用数组元素 引用数组元素可以利用数组下标获取引用数组元素可以利用数组下标获取ai,也可以利,也可以利用指针法获取用指针法获取appi与数组下标法相比,使用指针法引用数组元素一般情与数组下标法相比,使用指针法引用数组元素一般情况下能够使目标程序代码效率高,占用内存少,运行速度况下能够使目标程序代码效率高,占用内存少,运行速度快。
快app+i或或a+i都是数组元素都是数组元素ai的地址,即它们都指向的地址,即它们都指向数组数组a的第的第i个元素;个元素;*(app+i)或或*(a+i)则都表示数组元素则都表示数组元素ai,即数组,即数组a的第的第i个元素需要特别注意:需要特别注意: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 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);这个例子中,解这个例子中,解1和和2的方法的执行效率相同,的方法的执行效率相同,C编译器就是将编译器就是将ai作为作为*(a+i)来处理的。
而解来处理的而解3由于使用指针变量由于使用指针变量p,不必每次都重新计算元素不必每次都重新计算元素地址,利用高效的自加地址,利用高效的自加p+完成下个元素的定位完成下个元素的定位,所以效率会有所提高,由于所以效率会有所提高,由于通用指针通用指针p使用使用3个字个字节,效率会打折扣假如节,效率会打折扣假如p使用使用具体指针具体指针,效率,效率会更加突出会更加突出3.关于指针变量的运算关于指针变量的运算对于数组对于数组a10和同类型指针变量和同类型指针变量p=a:p+(或或p+=1)该操作将使指针变量该操作将使指针变量p指向下一个元素,即指向下一个元素,即a1,若再执行,若再执行x=*p则将取出元素则将取出元素a1赋值给赋值给x该操作还有跟使用环境有关:该操作还有跟使用环境有关:int*b=p+;则表示先把指针则表示先把指针p的当前值赋给指针变量的当前值赋给指针变量b,然后指针变量然后指针变量p指向下一个元素指向下一个元素p+由于运算符由于运算符+和和*的优先级别相同,而结合方的优先级别相同,而结合方向对向对p来说来说自左向右自左向右,所以该运算先执行,所以该运算先执行*p,然,然后再执行后再执行p+。
其作用是先得到指针变量其作用是先得到指针变量p指向的值即指向的值即*p,然,然后再执行后再执行p的自加运算假如没有使用环境,仅的自加运算假如没有使用环境,仅仅是执行仅是执行p的自加运算,等效于的自加运算,等效于p+;假如存在使;假如存在使用环境:用环境:int b=*p+;则相当于两条语句:则相当于两条语句:int b=*p;p+;请注意,它和请注意,它和(*p)+以及以及*(p+)都不相同都不相同区别:区别:n(*p)+nP指向的元素的内容自指向的元素的内容自+1n*(p+)n先执行()先执行()-P指向指向的元素自的元素自+1,即下一,即下一个元素个元素*p+与与*+p不同不同 前者在使用前者在使用p后进行后进行p的的自加,而后者则是在自加,而后者则是在使用使用p前就进行前就进行p的自加:的自加:int a10;int*p=a;分别执行下列语句:分别执行下列语句:int b=*p+;int c=*+p;前者得到的前者得到的b为为a0,而后者得到的,而后者得到的c为为a1,p在两种运算中最后的结果相同,都指向第二个元在两种运算中最后的结果相同,都指向第二个元素素a1p)+作用是对指针变量作用是对指针变量p所指向的元素值即所指向的元素值即*p执行执行自加运算,结果不影响指针自加运算,结果不影响指针p,但是影响,但是影响p所指的所指的第一个数组元素的值。
第一个数组元素的值P108,4 若若p指向数组元素中第指向数组元素中第i个元素:个元素:P108,5*(p-)与)与ai-等价;等价;*(+p)与与a+i等价;等价;*(-p)与与a-i等价;等价;所有这些运算都和运算环境有关所有这些运算都和运算环境有关下面以二维数组为例来说明多维数组的指针和指针变量下面以二维数组为例来说明多维数组的指针和指针变量的使用方法的使用方法(运行程序,编译运行程序,编译)指向多维数组的指针和指针变量指向多维数组的指针和指针变量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;定义指针变量定义指针变量int(*p)4的含义:的含义:p是一组指针变量是一组指针变量(共共4个个元素元素)的第一个指针变量的地址,这里数组元素是指针变量。
的第一个指针变量的地址,这里数组元素是指针变量假如指针变量元素的个数不确定,就可以定义成指针的指针假如指针变量元素的个数不确定,就可以定义成指针的指针int*pp=a指向数组指向数组a的第一个数组元素的地址后(的第一个数组元素的地址后(这里数组名这里数组名a可可以看做以看做a4数组的首地址数组的首地址p109):):p+1和和a+1等价指向数组等价指向数组a的第的第1行首元素地址;行首元素地址;p+2和和a+2等价指向数组等价指向数组a的第的第2行首元素地址;行首元素地址;:*(p+1)+3和和&a13等价指向等价指向a13的地址;的地址;*(*(p+1)+3)和和a13等价标示等价标示a13的值习题习题p.1231 1、2 2、9 9、1010Keil Cx51支持支持“基于存储器基于存储器”的具体指针的具体指针和和通用通用(一般一般)指针指针关于关于Keil Cx51的指针类型的指针类型1、基于存储器的指针基于存储器的指针p110 基于存储器的指针就是基于存储器的指针就是在在 指针的声明中包含一个存储指针的声明中包含一个存储类型标识符,指向一个确定的存储区,这种指针叫类型标识符,指向一个确定的存储区,这种指针叫具体指具体指针针。
例如:例如: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 str;/*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位偏移P111-112通用指针和标准通用指针和标准C 指针的声明相同指针的声明相同例如:例如:char *s;/*string ptr*/int *numptr;/*int ptr*/通用指针可访问通用指针可访问8051 存储空间内的任何变量存储空间内的任何变量基于存储器的指针基于存储器的指针其类型由其类型由C代码中相关的代码中相关的存储器类型决定,并在编译时确定,存储器类型决定,并在编译时确定,用这种指针用这种指针可以非常高效地访问相关的存储器可以非常高效地访问相关的存储器通用指针包含一个字节的类型描述字节,使通用指针包含一个字节的类型描述字节,使用时要考虑类型字节,并根据类型字节的内容进用时要考虑类型字节,并根据类型字节的内容进行不同的处理,所以对相关存储器的访问效率会行不同的处理,所以对相关存储器的访问效率会降低指针类型指针类型描述描述大小大小通用指针通用指针3字节字节xdata指针指针2字节字节code指针指针2字节字节idata指针指针1字节字节data指针指针1字节字节pdata指针指针1字节字节各种类型指针变量的字节数如下表所示:各种类型指针变量的字节数如下表所示:地址偏移地址偏移+0+1+2内容内容存储器类型存储器类型偏移量高位偏移量高位偏移量低位偏移量低位通用指针通用指针3个字节的含义:个字节的含义:第一个字节表明具体存储器的类型第一个字节表明具体存储器的类型:类型类型idata/data/bdataxdatapdatacode值值0 x000 x010 xFE0 xFF地址偏移地址偏移+0+1+2内容内容0 x010 x120 x34 其它类型值可能会导致不可预测的程序动作,具体类型其它类型值可能会导致不可预测的程序动作,具体类型值还和编译器的版本有关。
以值还和编译器的版本有关以xdata类型的类型的0 x1234地址地址为指针可以表示如下:为指针可以表示如下:在在Keil Cx51的头文件的头文件absacc.h,使用这个头文件,可利,使用这个头文件,可利用三字节通用指针作为抽象指针,为个存储器空间提供绝对用三字节通用指针作为抽象指针,为个存储器空间提供绝对地址存取技术地址存取技术对于具体指针的定义,可以使用下面任何一种方式:对于具体指针的定义,可以使用下面任何一种方式:char data*xd_ptr;data char*xd_ptr;其中第一种方式比较标准其中第一种方式比较标准include char*generic_ptr,mystring=Test output;char data*xd_ptr;下面的例子反映出使用具体指针比使用通用指针更加下面的例子反映出使用具体指针比使用通用指针更加高效,使用通用指针的第一个循环需要高效,使用通用指针的第一个循环需要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+;由于使用具体指针能够节省不少时间,所以由于使用具体指针能够节省不少时间,所以我们一般都不使用通用指针。
我们一般都不使用通用指针当你在程序中使用指针时,你应指定指针的当你在程序中使用指针时,你应指定指针的类型,确定它们指向哪个区域,如类型,确定它们指向哪个区域,如xdata或或code区,这样你的代码会更加紧凑,因为区,这样你的代码会更加紧凑,因为编译器编译器不必去确定指针所指向的存储区,不必去确定指针所指向的存储区,因为你已经进因为你已经进行了说明行了说明5.3 结结 构构结构的定义和引用结构的定义和引用结构数组结构数组指向结构类型数据的指针指向结构类型数据的指针结构的定义和引用 结构是一种定义类型,它允许程序员把一系结构是一种定义类型,它允许程序员把一系列变量集中到一个单元中,当某些变量相关的时列变量集中到一个单元中,当某些变量相关的时候,使用这种类型是很方便的候,使用这种类型是很方便的例如,用一系列变量来描述一天的时间例如,用一系列变量来描述一天的时间定义时、分、秒三个变量:定义时、分、秒三个变量:unsighed char hour,min,sec;定义一个天的变量:定义一个天的变量:unsighed int days;通过使用结构可以把这四个变量定义在一起,给他们通过使用结构可以把这四个变量定义在一起,给他们一个共同的名字。
声明结构的语法如下:一个共同的名字声明结构的语法如下:struct time_str unsigned char 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.结构体类型的结构体类型的嵌套定义嵌套定义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;struct 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;long 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、结构类型变量的引用 结构体一般不能作为一个整体参加数据处理,而参结构体一般不能作为一个整体参加数据处理,而参加各种运算和操作的是结构体的各个成员项数据。
对成加各种运算和操作的是结构体的各个成员项数据对成员的使用方式:员的使用方式:结构体变量名结构体变量名.成员名成员名注:相同结构体类型的变量可以相互赋值注:相同结构体类型的变量可以相互赋值struct person p1,p2;p1=p2;在在Keil C和大多数和大多数C编译器中,结构被提供了连续的编译器中,结构被提供了连续的存储空间,寻址空间内的变量顺序和定义时的变量顺序一存储空间,寻址空间内的变量顺序和定义时的变量顺序一样:样:OffsetMemberBytes0hour11min12sec13days24、结构体变量的存储结构 若数组中每个元素变量都具有相同的结构类若数组中每个元素变量都具有相同的结构类型,就构成一个结构数组型,就构成一个结构数组结构数组结构数组 结构数组与变量数组的不同之处,就在于结结构数组与变量数组的不同之处,就在于结构数组的每一个元素都是一个由若干个变量组成构数组的每一个元素都是一个由若干个变量组成的结构结构数组的定义方法与变量数组的定义方法结构数组的定义方法与变量数组的定义方法相似,只要把结构变量改称结构数组即可:相似,只要把结构变量改称结构数组即可:struct time_str oldtime10;指向结构变量的指针变量的定义和一般变量指向结构变量的指针变量的定义和一般变量指针的定义相似。
指针的定义相似指向结构类型数据的指针指向结构类型数据的指针 一个指向结构类型数据的指针,就是该数据一个指向结构类型数据的指针,就是该数据在内存中的首地址在内存中的首地址1、指向结构变量的指针变量、指向结构变量的指针变量 Struct 结构类型名结构类型名 *指针变量名;指针变量名;Struct 结构成员说明;结构成员说明;*指针变量名;指针变量名;#define uint unsigned int#define uchar unsigned charstruct uint lnk;uchar len,flg,nod,sdt,cmd,stuff;msg1;struct msg1 *p;/定义指针定义指针void rqsendmssage(struct msg1 *m);一个使用结构指针的简单例子:一个使用结构指针的简单例子:void main()uchar stuff=0;struct msg1*p;p-len=8;p-flg=0;p-nod=0;p-cmd=0;p-stuff=stuff;rqsendmssage(p);结构类型指针的运算规律也和一般变量指针的结构类型指针的运算规律也和一般变量指针的运算规律相似,区别运算规律相似,区别仅在于指针每次增加的单元是仅在于指针每次增加的单元是整个结构空间。
整个结构空间2、指向结构数组的指针变量、指向结构数组的指针变量 Struct 结构数组名结构数组名 *指针变量名;指针变量名;Struct 结构成员说明;结构成员说明;结构数组指针变量名结构数组指针变量名 ;指向结构数组的指针变量的定义指向结构数组的指针变量的定义#define uint unsigned int#define uchar unsigned charstruct uint lnk;uchar len,flg,nod,sdt,cmd,stuff;msg14;struct msg1 *p;void rqsendmssage(struct msg1*m);void main()uchar stuff=0;struct msg1*p;for(p=msg1;plen=8;p-flg=0;p-nod=0;p-cmd=0;p-stuff=stuff;rqsendmssage(p);3、指向结构数组的、指向结构数组的指针变量指针变量P的几点说明的几点说明如果指针指向结构数组如果指针指向结构数组msg1的首地址的首地址p119(*p).flg与与p-flg和和msg10.flg是完全等价的。
是完全等价的p+1使指针使指针p指向结构数组指向结构数组msg10的下一个元素的下一个元素msg11的首地址的首地址前前+,后,后+运算,与指向运算符运算,与指向运算符-p)-flg (p+)-flg p-flg+p-flg5.4 共共 用用 体(体(联合)联合)概念:概念:共用体是共用体是若干变量若干变量共用共用同一段内存单元的同一段内存单元的构造数据类型构造数据类型1、共用体类型共用体类型的定义的定义union 共用体类型标识符共用体类型标识符 类型说明符类型说明符 变量名;变量名;其中其中union是关键字;是关键字;共用体中的成员可以是共用体中的成员可以是简单变量简单变量,也可以是,也可以是数组数组、指针指针、结构体结构体和和共用体共用体2、共用体变量的定义、共用体变量的定义 共用体变量的定义和结构体变量相似,可以先说明共用共用体变量的定义和结构体变量相似,可以先说明共用体类型,再定义变量,也可以在类型说明的同时定义变量体类型,再定义变量,也可以在类型说明的同时定义变量union time_type unsigned long secs_in_year;struct time_str time;mytime;3、共用体变量的引用、共用体变量的引用 共用体变量中每个成员的引用方式与结构体变量完共用体变量中每个成员的引用方式与结构体变量完全相同,有以下三种形式:全相同,有以下三种形式:(1)共用体变量名共用体变量名.成员名成员名(2)(*指针变量名指针变量名).成员名成员名(3)指针变量名指针变量名-成员名成员名 同样,共用体中成员变量可以参与其所属类型允许同样,共用体中成员变量可以参与其所属类型允许的任何操作。
的任何操作像结构一样,联合也以像结构一样,联合也以连续的空间存储连续的空间存储,空间大小等,空间大小等于联合中于联合中最大的成员最大的成员所需的空间所需的空间OffsetMemberBytes0Secs_in_year40Mytime54、共用体变量的存储结构、共用体变量的存储结构union time_type unsigned long secs_in_year;struct time_str time;mytime;共用体共用体经常被用来提供同一个数据的不同的表达方式经常被用来提供同一个数据的不同的表达方式5、共用体的应用、共用体的应用union status_type unsigned char status4;unsigned long status_val;io_status;io_status.status_val=0 x12345678;if(io_status.status2&0 x10)例如:一个长整型变量用来存放四个寄存器的值,如果希望对这些数例如:一个长整型变量用来存放四个寄存器的值,如果希望对这些数据有两种表达方法,可以在联合中定义一个长整型变量,同时再定义据有两种表达方法,可以在联合中定义一个长整型变量,同时再定义一个字节数组:一个字节数组:5.5 枚枚 举举 如果一个变量只有若干种可能的取值,可以将变量的如果一个变量只有若干种可能的取值,可以将变量的所有取值一一列出,声明一个枚举类型,再将该变量定义所有取值一一列出,声明一个枚举类型,再将该变量定义为此枚举类型,则该变量的值就只能限于此枚举类型所列为此枚举类型,则该变量的值就只能限于此枚举类型所列举出来的值的范围内。
举出来的值的范围内1、枚举类型枚举类型和和枚举类型变量枚举类型变量的定义的定义enum 枚举名枚举名 枚举表枚举表 变量列表变量列表;enum 枚举名枚举名 枚举表枚举表;enum 枚举名枚举名 变量列表变量列表;例:例:enum color red,blue,black,pink,white,yellow;/*声明枚举类型声明枚举类型enum color */enum color c;/*定义了枚举变量定义了枚举变量c */枚举表是由若干用户定义的标识符(如枚举表是由若干用户定义的标识符(如red、blue)组成,这些符号通常称为枚举元素组成,这些符号通常称为枚举元素例:例:enum _Time A1=1,B1=3,C1=7 data eTime;此行代码在此行代码在RAM的的data区定义一个具有区定义一个具有3个元素的枚举个元素的枚举变量变量eTime,它可以取值,它可以取值A1、B1、C1必须注意,其中的必须注意,其中的A1、B1、C1不能和已经定义的其他符号冲突不能和已经定义的其他符号冲突2、枚举变量枚举变量的取值的取值(1)枚举表中,枚举表中,每一项符号代表一个整数值每一项符号代表一个整数值。
在默认的情况在默认的情况下,第一项取值为下,第一项取值为0,第二项取值为,第二项取值为1,第三项取值为,第三项取值为2,依次类推依次类推例:例:enum _Time A1,B1,C1,data eTime;各符号元素去默认值各符号元素去默认值A1=0、B1=1、C1=22)也可以通过初始化,指定某些项的符号值也可以通过初始化,指定某些项的符号值例:例:enum _TimeA1,B1=10,C1 data eTime;各符号元素取值各符号元素取值 A1=0、B1=10、C1=11各符号元素在没有给定具体整数值时取默认值,默认值总是比上各符号元素在没有给定具体整数值时取默认值,默认值总是比上一个元素大一个元素大1,第一个元素的默认值总是,第一个元素的默认值总是0习题习题p.1234 4、1212、1414。