版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、1,C51数据类型,基本类型 字符型(unsigned char, signed char) 1字节 8位 整型基本型(unsigned int, signed int) 2字节 16位 长整型(unsigned long, signed long) 4字节 32位 C51中short int 等同于int 实型单精度(float) 4字节 7位有效数字 双精度(double) 4字节 7位有效数字 位型 (bit) 1位 构造类型 数组类型 结构体类型 共用体 枚举 指针类型 空类型,第三章,1,第五章CX51构造数据类型,2,5.1数组,对于变量 基本类型单个出现的变量,每个变量可以代表一
2、个确定的数据(变量值),且具有一定属性。 如 static int x,y; 但变量间不存在确定的相互关系。 构造类型由基本类型按一定规则组成。其中: 数组:由一组有序数据(数组元素)组成。 每个元素:有相同类型,统一数组名; 用下标(index)确定其顺序;但可以取各自值。 如 static int a5; 其中: 表示a是个数组,而不是一个简单变量a。 5表示该数组共有5个元素,元素编号从0开始,a0表示第1个元素,a4表示第5个元素(最后一个),3,5.1.1 数组的定义,同变量一样,数组也必须“先定义,后使用”。 定义内容: 数组名(同变量名:字母、下划线、数字;字母或下划线开头;长度
3、32) 类型(存储属性/数据类型) 大小(维数/元素个数) 定义的一般形式: 存储属性 数据类型 存储类型 数组名常量表达式常量表达式 注意:数组长度必须是常量表达式 常量或符号常量,其值必须为正,不能为变量。,数组长度 (数组元素最大个数),4,5.1.1 数组的定义,错误: int n=5; int an;,正确: #define N 5 int aN;,正确: int a10,b54; char name8,ch23; float xdata x8*2+1,table234; #define NUM 40; int aNUM,bNUM+2;,5,5.1.2 一维数组和多维数组,一维数组
4、用一个下标来确定各元素在数组中的顺序。可用排列成一行的元素组来表示。 如 int a5; (右上图) 二维数组 用两个下标来确定各元素在数组中的顺序。可用排列成ij列的元素组来表示。 如 int b23; (右下图) n维数组 用n个下标来确定各元素在数组中的顺序。 如 int c324; n3时,维数组无法在平面上表示其各元素的位置。,n维数组的元素总数等于各维长度之和(积)。,特别注意 数组名表示每个数组的首地址,即: a 表示 int idata b23=1,2,3,4,5,6; 或 int idata b23=1,2,3,4,5,6; 简略形式: 1、省略第一维数组大小。如: int
5、idata a =,b 3=; 2、省略元素值。如: int idata x6=1,2,3,4; (x4、x5自动用0补足) int data a5=0; int b32=0; (全部元素初始化为0),7,5.1.3 数组的初始化(赋初值),【例一】以下程序的赋值结果是什么? main() int a 3=1,2,3,4,5,6,0; ,1 2 3 4 5 0 6 0 0 0 0 0,结果:5, 0, 0,【例二】若int a 3=1,2,3,4,5,6,7,则a数组的第一维大小是多少?,1 2 3 4 5 6 7 0 0,8,5.1.3 数组的引用(使用数组元素),原则:先定义后引用 引用形
6、式: 数组名下标 只能逐个引用数组元素,不能一次引用整个数组。 引用数组元素要注意下标不要出界(编译程序不检查是否“出界”)。 每个数组元素均可按一个简单变量的方式进行处理(如参加运算、赋值等)。,9,5.1.3 数组的引用(使用数组元素),(设已有定义int idata a26,x,y ,i=0,j=0;) a23=4; /*下标为常量*/ y=sqrt(a23); aij=20; /*下标为 int 型变量i,j) */ ai-1j*3-1 = 1; /*下标为一个复杂的整型表达式*/ 错误: a2,3=1,调试时,可将数组名或数组元素名设置为watch进行跟踪.,10,讨论:如果下标值小
7、于0或超过数组长度时会出现什么情况?,例: main() int a=1,b5,c=2,i; for (i=0;i=5;i+) bi=i+1; ,运行程序或单步执行观察变量变化情况可以看到,变量c的值因数组越界而被悄悄破坏了(可能产生严重的错误后果!),1,2,3,4,5,6,0,1,2,3,4,5,6,5.1.3 数组的引用(使用数组元素),11,数组常用的循环形式,法一 int i,a100; for(i=0;i100;i+) ai=i;,法二 int i,a100; for(i=0;i=99;i+) ai=i;,C程序中常用的是第一种方法。注意在此法中,循环变量的终值是“小于”而非“等于
8、”数组长度!否则将导致“越界”的发生。,12,如何使两个数组的值相等,/*错误编程*/ main() int a4=1,2,3,4,b4; a=b; ,解决方法 法1:逐个元素赋值 b0=a0; b1=a1; b2=a2; b3=a3; 法2:通过循环赋值 int i; for (i=0;i4;i+) bi=ai;,原因: 数组名表示数组的首地址,其值不可改变!,13,5.1.4 字符数组和字符串,【字符数组】存放字符(每个数组元素存放一个字符),1、字符数组的定义 如: char a10; char a23;,字符数组各个元素分别存放一个字符的数组。 字 符 串 “” (字符串常量)以“0”
9、结尾。 实际使用中,可以将字符串看成是特殊的字符数组(以“0”为最后一个元素值)。如字符串”xy12”可以看成: int a5=x,y,1,2,0;,14,字符数组的初始化,单字符方式 char a10=A, B, C, D; char b23= A, B, C, D, E,F; 【注意】如果初值个数小于数组长度,则多余的数组元素自动为空字符(0) 字符串方式 char a5=“ABCD”; char c =”ABCD”; char a25=A,B,C,0,x,y,0; char a25=“ABC”,”XY”; 二维字符数组可以认为由若干个一维字符数组(字符串)组成。,15,示 例,【例一】比
10、较以下字符数组长度是否相同: char a =”ABCD”; char b = “ABCD”; char c =A,B,C,D; 【例二】下列程序段的a的运行结果是: char a5=a,b, 0,d,0;,16,5.1.5 与数值数组有关的常用算法,排序:起泡法/选择法/插入法 查找:顺序查找法/折半查找法 矩阵运算 1、常用排序算法 起泡法(冒泡法/气泡法) 有n个杂乱无序的数,要求将这n个数从小到大(或从大到小)排序后输出。 选择法 从算法优化的角度对“冒泡法”进行改进。 冒泡法每一轮都要将数组中的数两两比较,并根据大小交换之效率低。 选择法改进处:两两比较后并不马上交换,而是找到最小数
11、后记下其下标。在一轮比较完毕后,再将最小的数一次交换到位。比较次数不变,交换次数减少。,17,5.1.5 与数值数组有关的常用算法,插入法 如果有N个元素,也是要比较N-1轮,但每轮取第i个(i从1开始)元素的值为暂存值m,然后与左边的各数(从j=i-1开始)比较一直到左边第一个(j=0)为止。如果m比左边大,就让左边的值右移,最后将该轮的第i个数插到左边的合适位置(如果它比较大的话)。 2、查找法 顺序查找法 对半搜索法 3、矩阵运算,18,在二维字符数组中,双下标引用表示某行某列的某个元素 单下标引用表示某行的字符串,【例三】分析以下程序的运行结果: main() char word310
12、; int i; for (i=0;i3;i+) scanf(%s,wordi); printf(%s,wordi-2); ,运行时,输入: 12345 abcdef ABCDEFG,wordi表示第i+1行word元素首地址(二维数组用单下标表示某行的字符串),结果:abcdef,注意,19,5.1.6 数组的存储结构,根据数组的数据类型,为每一元素安排相同长度的存储单元。 根据数组的存储属性,将其安排在相应的存储区域。 注意: 在进行CX51编程开发时,要仔细地选择数组的大小。,20,5.2 指针,5.2.1 指针的基本概念 1地址(address) 如果在程序中定义了一个“实体”(变量、
13、数组、函数 ),编译时系统就要给这些实体分配内存单元。 分配规则:,21,什么是内存单元“地址”?,内存单元是以字节为单位,每个字节都有一个编号(即“地址”)。如果将内存比作一个旅馆,内存单元就好比“床位”,而实体则好比“旅客”。这些“旅客”(实体)中,有单人型(char)、夫妇型(int)、家庭型(float,long,double等),还有团体型(数组等)。每个“实体”占用的内存单元是不同的。如: char a;int b;float c;int d3;int max( ),22,内存单元与地址,main() char xdata a; int xdata b; float xdata c
14、; int xdata d3; int xdata max( ); ,地址,通常我们关心的不是各个内存单元的具体地址值,而是每个实体的“起始地址”。,23,如何表示实体地址?,实体地址表示法1:直接访问(实体名) 普通变量a,b,c char *b; float *c;,通常在CX51语言中,所谓“指针”就是指“指针变量”。 从现在开始,我们所说的“指针”除非另加说明,否则均表示“指针变量”。,是不是说地址有”整型” , ”字符型” , ”实型” 之分?,习惯用语: 若指针变量p存放了变量a的地址,我们称“p指向a”。,26,指针变量不要谈”指”色变,指针是CX51语言学习中的一大难点。 难难
15、在概念。,main() int idata a,*p1,*p2= ,学了半天,我还是一头雾水,27,首先搞定*p,请看以下变量声明语句 int data a,*p1; char idata b,*p2; a,b 普通变量(存放某个数值或字符) p1,p2 指针变量(存放某个实体的地址),如果是 int idata *a,p1; char idata *b,p2;,变量声明时,如果变量名前带 *号,表示该变量是个指针变量,28,注意不同的*p,以下程序中哪些语句是错误的? main() int a,*p; a=3; p=3; /*或者 p=a;*/ p= /*或者*p=3*/ ,讨论: 程序中引
16、用变量时, 对指针变量p, 不带*号引用表示? 带*号引用表示?,两个特殊的运算符 p= ,main() int *p,a12=1,2,3,4,5; p=a; for ( ;*p5;p+) printf(%d,*p); ,结果:a=13,b=10,结果:1234,32,p指向字符数组时的*p,如果p被定义成指向某个字符数组或某个字符串的指针变量,则*p代表某个字符。 如 int *p, a3=”abcd”; p=a; p代表a中的某个字符,main() char *p,a12=abcde; p=a; for (;*p;p+) printf(%c,*p); ,main() char *p; p=
17、abcde; for (;*p;p+) printf(%c,*p); ,如果直接用a进行循环,行不行?,在for语句中用*p控制循环,是否适用于数值数组?,错了吧! ,33, p= * int *p; x=3.14; p= ,结果:y=-2621.000000,怎么会这样?,把int *p改为float *p后,结果正确:y=3.140000,35,指针变量能参加运算吗?,指针变量和其他变量一样,可以在各种表达式中参加运算。 但指针变量和普通变量不同,只能进行以下三种运算: 赋值运算 算术运算 指针比较,36,指针变量的赋值运算,指针变量初始化 变量声明时赋值,main( ) int a=5,
18、*p= printf(“%d,%d,%dn”,p,*p,a) ,指针变量一般赋值 程序处理时赋值,结果:2000,5,5,main() int x; int *p1,*p2; p1= ,37,典型错误,指针变量定义后,未指向具体存储单元(实体地址)就使用,此时指针变量所指单元是任意的, 是个”危险指针”。,【例一】若有定义 char *a,b30; 则以下各语句正确的是 : A) a=”abcde”; B)b=”abcde”;,38,字符指针变量与字符数组 char *cp; 与 char str20; str由若干元素组成,每个元素放一个字符;而cp中存放字符串首地址 char str20;
19、 str=“I love China!”; () char *cp; cp=“I love China!”; () str是地址常量;cp是地址变量 cp接受键入字符串时,必须先开辟存储空间,例 char str10; scanf(“%s”,str); () 而 char *cp; scanf(“%s”, cp); (),改为: char *cp,str10; cp=str; scanf(“%s”,cp); (),39,为什么未指向实体的指针是“危险指针”?,“危险指针”?不要耸人听闻好不好!,一个指针未指向任何实体就被使用,属于”内存盗用”!因为该指针将随意指向内存中某一单元,轻则误取或破坏
20、其他实体的值,重则破坏操作系统的工作。,一个指针变量被声明后,在没有被赋予某个实体地址之前,如果使用它,不仅可能破坏你的程序,而且可能导致计算机操作系统崩溃,出现灾难性的错误。因为它可能指向内存的任何部分。,40,空指针,空指针: int *p; p=NULL;,NULL是什么? 在stdio.h中,定义 #define NULL 0 所以 p=NULL; 相当于 p=0;,41,讨论:以下程序中的*p1,*p2,#include main() int *p1=NULL,*p2; clrscr(); *p1=100; *p2=200; printf(%d,%dn,*p1,*p2); ,*p1有
21、确定地址,但未指向任何变量,*p2无确定地址,是“危险指针”,在指针p指向某个实体的地址之前,不可对*p进行赋值。否则可能发生意想不到的错误(p随便指向某个单元)。,42,指针变量的算术运算,指针只有两种算术运算加、减 p+5 p+ p-1 p- 注意加减运算是以实体为单位而不是以字节为单位。 此外,两个指针变量可以相减。即:如果两个指针变量指向同一数组时,两个指针变量值之差是两个指针之间的元素个数。 但两个指针变量相加并无实际意义。,43,以下程序哪个语句执行时会出错?,#include main() int a10,*p1=a; a+; p1+; ,X,44,注意事项, 注意指针变量当前值
22、 注意不要超界 常见表示法: 设指针变量p指向数组a (即p=a)。 1、p+(或p+=1) 使指针变量p指向下一个数组元素,即a1。 2、*p+ 结合方向为自右向左。它等价于*(p+), 其作用是先得到p指向的变量的值(即*p),然后再执行p自加运算。 3、*p+ 与 *+p作用不同 前者先取*p值,后使p自动加1; 后者先使p自动加1,再取*p值。 4、(*p)+ 表示p所指向的元素值加1。要注意的是元素值加1而不是指针变量值加1。若指针变量p指向此时a0值增为4。 5、若p当前指向数组中第i个元素,则: *(p-)与ai-等价,相当于先执行*p,然后再使p自减; *(+p)与a +i等价
23、,先执行p自加,再执行*p运算; *(-p)与a-i等价,先执行p自减,再执行*p运算;,45,示 例,#include #include void main(void) char data *p1,*p2,*p3,*p4,*px; char x=1,2,3,4; char px1,px2,px3,px4; #ifndef MONITOR51 SCON = 0 x50; /* SCON: mode 1, 8-bit UART, enable rcvr */ TMOD |= 0 x20; /* TMOD: timer 1, mode 2, 8-bit reload */ TH1 = 221; /
24、* TH1: reload value for 1200 baud 16MHz */ TR1 = 1; /* TR1: timer 1 run */ TI = 1; /* TI: set TI to send first char of UART */ #endif px=p1=p2=p3=p4=x; px1=*p1+; p2=p1+2;,px2=*-p2; px3=(*p3)+; /*x0=2*/ px4=*(p4+); P1=P10 x01; printf(The start address of Array x is %Pn,px); P1=P10 x01; printf(px1= %b
25、d, p1= %Pn,px1,p1); P1=P10 x01; printf(px2= %bd, p2=%Pn,px2,p2); P1=P10 x01; printf(px3= %bd, p3=%Pn,px3,p3); P1=P10 x01; printf(px4= %bd, p4=%Pn,px4,p4); ,The start adderss of Array x is I 002C px1=1, p1=I:002D px2=3, p2=I:002E px3=1, p3=I:002C px4=2, p4=I:002D X=2,2,3,4,46,5.2.2 数组指针和数组的指针变量,1、一维数
26、组中的有关规定,一维数组中p=a时,p和a都可以相互替换。,有一个地方不能替换,知道是什么地方吗?,p+不能用a+替换!,为什么?,因为a是常量,5+即5=5+1是个低级错误!,47,小结:C51语言的有关规定,对一维数组的数组名 a: 数组名a代表数组首地址(数组第一个元素a0的地址) 即: a= 则 p 和 a 在程序中实际上可以互相替换使用。 p= int *p,i,j=0; p=a; /* for (i=0;i9;i+) */ printf(%dn,*(a0+i); ,Lets try 1、将a0改为 a1、a2 int *p,i; p=a; for (i=0;i3;i+) print
27、f(%d ,a+i); printf(%d %d %dn, ,改成*(a+i)、ai分别试试 再把%d改为%p试试,【注意】二维数组中,ai、a+i与*(a+i) 等价 原因:a+i 不是变量,C51规定ai 、a+i与*(a+i) 等价。,53,看一个例子,main() int a33=1,2,3,4,5,6,7,8,9; int *p,i,j; p=a; for (i=0;i3;i+) for(j=0;j3;j+) printf(%d ,*(*(a+i)+j); ,改成aij试试,54,用简单指针变量指向二维数组时,用简单指针变量指向二维数组时: int a1010,*p; p=a; p都
28、是列地址性质的指针(姑且称“列指针”)。此时,p可与“排队法”中的a互换使用,但不能与“行列法” 中的a0互换使用。,55,比较一下,main() int a33=1,2,3,4,5,6,7,8,9; int *p,i; p=a; for (i=0;i9;i+) printf(%dn,*(p+i); ,1 2 3 4 5 6 7 8 9,换成*(a0+i)试试,56,再看下一个例子,main() int a33=1,2,3,4,5,6,7,8,9; int *p,i,j; p=a; for (i=0;i3;i+) for(j=0;j3;j+) printf(%d ,*(*(a+i)+j); ,
29、a改成p试试,【讨论】 如果将输出语句中的*(*(a+i)+j)改为*(*(p+i)+j)可不可以?,不行!,Why?!,因为p不是“行指针”!,57,行指针,形式: int (*p)n 含义:p为指向含有n个元素的一维数组的指针变量。 使用:二维数组可以视为由若干一维数组组成。 行指针p是行地址性质的指针。此时,p可与“行列法”中的a互换使用,但不能与“排队法”中的a0互换使用。,58,行指针是如何使用的?,若 int a45; int (*p)5; p=a;或p=a0; 则 (*p)0=a00; (*p)1=a01; (*p)2=a02; (*(p+1)0=a10; (*(p+1)1=a1
30、1; ,行指针是一种行地址,可以与二维数组用数组名表示的行地址互换使用。 事实上,有 (*(p+ i)j=pij= * (*(p+ i)+j)=aij;,59,示例一,main() int a33=1,2,3,4,5,6,7,8,9; int (*p)3,i,j; p=a; for(i=0;i3;i+) for(j=0;j3;j+) printf(%d ,*(*(p+i)+j); ,结果:1 2 3 4 5 6 7 8 9,60,示例二,若有以下定义和语句,且0i4,0j3,则不能访问a数组元素的是 。 int i, (*p)3; int a 3=1,2,3,4,5,6,7,8,9,10,11
31、,12; p=a; A)*(*(a+i)+j) B)pij C)(*(p+i)j D)pi+j,答案:D (pi+j是个地址),61,示 例,#include #include void main(void) int a34=1,3,5,7,9,11,13,15,17,19,21,23; int (*p)4,i,j; #ifndef MONITOR51 SCON = 0 x50; /* SCON: mode 1, 8-bit UART, enable rcvr */ TMOD |= 0 x20; /* TMOD: timer 1, mode 2, 8-bit reload */ TH1 = 2
32、21; /* TH1: reload value for 1200 baud 16MHz */ TR1 = 1; /* TR1: timer 1 run */ TI = 1; /* TI: set TI to send first char of UART */ #endif p=a; i=2; j=2;,printf(a%d,%d=%dn,i,j,*(*(p+i)+j); printf(The address of p is %P, the address of a is %Pn,p,a); printf(The address of p+1 is %P, the address of a+
33、1 is %Pn,p+1,a+1); printf(The address of p+1 is %P, the address of a+1 is %Pn,*(p+1),。,62,指针数组,定义: char *p5; 功能:定义数组p5,其每个元素 p0、p1、p4都是指针变量。通常用于指向一组字符串。 此时,对于pi,其下标表示第i个字符串,pi本身是第i个字符串的首地址。,63,指针数组赋值与初始化,64,char name59=“gain”,“much”,“stronger”, “point”,“bye”;,char *name5=“gain”,“much”,“stronger”, “p
34、oint”,“bye”;,二维数组与指针数组区别:,二维数组存储空间固定 字符指针数组相当于可变列长的二维数组 分配内存单元=数组维数*2+各字符串长度,指针数组元素的作用相当于二维数组的行名 但指针数组中元素是指针变量 二维数组的行名是地址常量,65,main() int b23,*pb2; int i,j; for(i=0;i2;i+) for(j=0;j3;j+) bij=(i+1)*(j+1); pb0=b0; pb1=b1; for(i=0;i2;i+) for(j=0;j3;j+,pbi+) printf(b%d%d:%2dn,i,j,*pbi); ,例 用指针数组处理二维数组,6
35、6,例 对字符串排序(简单选择排序),main() void sort(char *name,int n), print(char *name,int n); char *name=Follow me,BASIC, Great Wall,FORTRAN,Computer ; int n=5; sort(name,n); print(name,n); void sort(char *name,int n) char *temp; int i,j,k; for(i=0;i0) k=j; if(k!=i) temp=namei; namei=namek; namek=temp; ,i=0,67,例
36、对字符串排序(简单选择排序),main() void sort(char *name,int n), print(char *name,int n); char *name=Follow me,BASIC, Great Wall,FORTRAN,Computer ; int n=5; sort(name,n); print(name,n); void sort(char *name,int n) char *temp; int i,j,k; for(i=0;i0) k=j; if(k!=i) temp=namei; namei=namek; namek=temp; ,name0,name1,n
37、ame2,name3,name4,name,Great Wall,FORTRAN,Computer,Follow me,BASIC,i=1,68,例 对字符串排序(简单选择排序),main() void sort(char *name,int n), print(char *name,int n); char *name=Follow me,BASIC, Great Wall,FORTRAN,Computer ; int n=5; sort(name,n); print(name,n); void sort(char *name,int n) char *temp; int i,j,k; fo
38、r(i=0;i0) k=j; if(k!=i) temp=namei; namei=namek; namek=temp; ,name0,name1,name2,name3,name4,name,Great Wall,FORTRAN,Computer,Follow me,BASIC,i=2,69,例 对字符串排序(简单选择排序),main() void sort(char *name,int n), print(char *name,int n); char *name=Follow me,BASIC, Great Wall,FORTRAN,Computer ; int n=5; sort(na
39、me,n); print(name,n); void sort(char *name,int n) char *temp; int i,j,k; for(i=0;i0) k=j; if(k!=i) temp=namei; namei=namek; namek=temp; ,name0,name1,name2,name3,name4,name,Great Wall,FORTRAN,Computer,Follow me,BASIC,i=3,70,例 对字符串排序(简单选择排序),main() void sort(char *name,int n), print(char *name,int n);
40、 char *name=Follow me,BASIC, Great Wall,FORTRAN,Computer ; int n=5; sort(name,n); print(name,n); void sort(char *name,int n) char *temp; int i,j,k; for(i=0;i0) k=j; if(k!=i) temp=namei; namei=namek; namek=temp; ,name0,name1,name2,name3,name4,name,Great Wall,FORTRAN,Computer,Follow me,BASIC,71,示例,mai
41、n() char *str =AA,BB,CC; str1=str2; printf(%s,%s,%sn,*str,str1,*(str+2); ,结果:AA,CC,CC,指针数组常用于指向出错信息的指针,72,5.2.3 KEIL CX51的指针类型,KEIL C51有两种指针类型:基于存贮器的指针和一般指针。 KEILC51的指南针类型定义为: 数据类型 存储器类型1 * 存储器类型2 标识符 其中 数据类型是该指针变量所指向的变量的类型; 数据标识符是所定义的指针变量名; 存储器类型1、2是可选项。 若有存储器类型1 选项,则为基于存储器的指针,否则为一般类型指针。 (1)存贮器类型1确
42、定该指针变量所指向变量的存储区域,若存贮器类型1省略,在编译时根据编译模式,确定该指针变量指向变量所在的默认存储区; (2)存贮器类型2确定该指针变量本身所在的存储区域,若省略根据编译模式确定该指针所在的默认存储区域。,73,KEIL CX51的基于存贮器的指针,基于存贮器指针的定义(快速、节省存储器空间) 存贮器类型1确定该指针变量所指向变量的存储区域,可选择为idata *,data *,pdata *,code *,xdata *,这些指针的长度可为 1个字节(idata*, data*, pdata*) 2个字节(code*, xdata*); 存储器类型2为该指针变量本身所在的存储区
43、域,可选择为idata, data , pdata, code , xdata .,基于存贮器的指针定义举例: char xdata *px; 在xdata存贮器中定义了一个指向字符类型(char)的指针变量px。 它位于默认的存贮区,长度为2个字节,用于存放字符类型变量的地址(地址是2个字节,因为这个字符型变量位于外部RAM区域(xdata),但字符型变量占一个字节; char xdata * data pdx; 在xdata存贮器中定义了一个指向字符类型的指针,长度为2个字节。 同时,它明确定义指针变量pdx位于8051内部存贮区(data)。 data char xdata *pdx;
44、本例与上例完全相同。 data(存贮器类型2)可以放在定义的开头,也可以直接放在定义的对象名之前。(不建议这样做),病句,74,KEIL CX51的一般指针,一般指针包括三个字节:2字节偏移和1字节存贮器类型。 存贮器类型决定了对象所用的8051的存贮空间,偏移量指向实际地址。 一个“一般指针”可以访问任何变量而不管它在8051存贮空间中的位置。 存贮器类型编码如下:,【注意】:使用其它类型值可能会导致随机的程序动作。,75,KEIL CX51的指针类型,例:以xdata类型的0 x1234地址作为指针可以表示如下:,例:将常数值0 x41写入地址为0 x8000的外部数据存贮器中。 defi
45、ne XBYTE (unsigned char*) 0 x10000L) XBYTE0 x8000=0 x41; 赋初值。 其中:XBYTE被定义为(unsigned char*) 0 x10000L, 0 x10000L为一般指针,存贮类型为0 x01(xdata),偏移量为0000;所以XBYTE成为指向xdata零地址的指针。 XBYTE0 x8000是外部数据存贮器的0 x8000绝对地址。 绝对地址被定义为long型常量,低16位包含偏移量,高8位表明存贮器类型,为了表示这种指针,必须用长整型来定义。,当用常数作为指针时,必须注意正确定义存贮类型和偏移量。,76,一般指针与基于存储器
46、指针转换规则,一般指针用GP表示 GPxdata:使用GP的偏移部分(2字节) GPcode:同上 GPidata:使用GP偏移部分的低位(1字节),高字节不用 GPdata:同上 GPpdata:同上 xdataGP:一般指针的存储器类型编码被设定为0 x01,使用xdata * 的双字节偏移量; codeGP:一般指针的存储器类型编码被设定为0 xFF,使用code *的双字节的偏移量; idataGP:一般指针的存储器编码被设定为0 x00,指针的一字节偏移量被转换为unsigned int 类型。 dataGP:同上 pdataGP:一般指针的存储器类型编码被设定为0XFE,指针的一字
47、节偏移量被 转换为unsigned int 类型。,77,5.3结构体,1概述 数 组 是构造类数据,其数组元素必须是同一数据类型的。 结构体 也是构造类数据,但其成员可以是任何类型的。 构造类型使用户可以象处理单个变量一样来处理复杂的数据结构。,诸如学生花名册、通讯录之类的数据,最适合用结构体来处理。因为这类数据具有如下特点: 每个人信息都是一个复合的构造数据,如由姓名、学号、性别、年龄、家庭住址、联系电话等“成员”组成。 不同的人,数据的值不同,但都有共同的成员组成。,78,使用结构体的一般步骤,根据问题的要求定义一个结构体类型 用自己定义的结构体类型定义结构体变量 在程序中使用结构体变量
48、处理问题 比较普通变量的情况: 用系统给定的数据类型定义变量 在程序中使用变量处理问题,79,如何定义结构体类型?,struct 结构体名 类型标识符 成员名; ;,关键字 用户指定,/*struct 结构体名合称“结构类型标识符”*/,/*成员表列*/,/*此处分号不能省略*/,80,一个示例,【例一】 main() struct student int number; char name6; char sex; int age; char address20; ; ,本质上,它定义了一个名为”student”的“结构体类型”(表头)。,81,小结:什么是“结构体类型”?,用户自己定义的构造
49、型数据类型 由若干数据项(成员)组成 同一结构体中的成员可以具有不同的数据类型 注意成员定义与普通变量定义的区别: 成员定义时不为其分配内存 变量定义时为其分配内存,82,结构体类型的特点,组成结构体的成员本身必须是一种已有定义的数据: 基本类型成员(整型/字符型/实型) 指针类型成员 数组类成员 其他构造类成员(包括已定义的另一种结构体) 注意:成员变量,故成员名可与变量名同名 结构体类型可以有千千万万种,表示由若干不同数据项组 成的复合类型。 定义结构体类型时,系统不会为该结构体分配内存(只是定义类型,而非变量声明),83,结构体类型变量的定义,定义了以上结构体类型后,struct stu
50、dent 相当于标准数据类型关键字char, int ,float我们可以用它来定义“结构体变量”。 在结构体类型定义后,用 struct 结构体名 复合词定义 struct 结构体名 ; struct 结构体名 变量名1,变量名2, 变量名n; 如:struct student a,b30,*p; a 为struct student类型的变量 b 为struct student类型的数组(每个元素都是一个结构 体变量,都有众成员) p 为指向struct student类型的指针变量,84,还有两种合二为一方法, 在定义结构体类型的同时定义结构体类型变量 struct 结构体名 变量名1,变
51、量名2, 变量名n; 直接定义结构体类型变量 struct 变量名1,变量名2, 变量名n;,85,【例二】定义结构体类型的同时定义结构体类型变量。 main() struct student int number; char name6; char sex; int age; char address20; a,b30,*p; ,【例三】不定义结构体类型,直接定义结构体类型变量。 main() struct int number; char name6; char sex; int age; char address20; a,b30,*p; ,86,其他有关知识,实际使用中,还可以使用以下
52、形式: #define STU struct student STU stu1,stu2; 比较一下两种变量定义方式的异同: int a,b,c; 定义三个整型变量,每个变量占二个字节,可单独赋值。 struct student a,b,c; 定义三个结构体类型变量,每个变量下有若干“成员”。其占用的内存长度等于各成员项长度之和。,87,示例,【例四】 main() struct student int number; char name6; char sex; int age; char address20; ; printf(%dn ,sizeof(struct student); ,结果
53、: 31,88,示例,【例五】若有以下定义,则正确的赋值语句为 。 struct complex float real; float image; ; struct value int no; struct complex com; val1; A) com.real=1; B) plex.real=1; C) .real=1; D) val1.real=1;,答案:C).real=1,89,结构体变量的初始化和赋值,使一个结构体变量获得数据“值”(实际上是给其各个成员赋值)有三种方法: 定义时初始化之 用赋值语句对各成员分别赋值 同类型的结构体变量间相互赋值 如 student1=stude
54、nt2,90,示例: 定义时初始化,【例六】 main() struct char name15; char class12; long num; stu=Wenli,Computer,200113; printf(%sn%sn%ldn,,stu.class,stu.num); ,结果:Wenli Computer 1 200113,91,示例: 用赋值语句对各成员分别赋值,【例七】 main() struct char name15; char class12; long num; stu=Wenli,Computer,200113; 0=1; stu.cla
55、ss2=A; stu.num=1111; printf(%s,%s,%dn,,stu.class,stu.num); ,结果: 1enli,CoAputer,1111,92,示例: 用赋值语句对各成员分别赋值,【例七】 main() struct char name15; char class12; long num; stu=Wenli,Computer 1,200113; 0=1; stu.class2=A; stu.num=1111; printf(%s,%s,%dn,,stu.class,stu.num); ,结果: 1enli,CoAp
56、uter 1,1111,93,结构体变量的引用,只能引用其成员变量 用圆点(成员运算符)优先级最高 如 val1.no+ sum=.real+.image 可以将成员变量按普通变量运算方式处理,包括取地址: char name20; char sex; int age; float score; char addr30; ; struct student stu3;,定义结构体时同时定义 struct student int num; char name20; char sex; int age; float score; char addr30; stu3;,95,5、结构体数组,初始化 一般初始化 省略维数 定义后初始化,一般初始化 struct student int num; char name20; char sex; int age; float score; stu3= 10101,李宁,M,18,87.5, 10102,张凡,M,19,99, 10103,王敏,F,20,78.5 ;,定义后初始化 struct student int num; char name20; char sex; int age; float score; ; struct student stu3= 10101,李宁,M,18,87.5, 10102,张凡,M,19,99,
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 钳工考试题库宝典及答案
- 人教版地理八年级上学期期末综合测试(含答案)
- 辅警法治培训
- 蛋种鸭养殖技术培训课件
- 2026年深圳中考语文考前3天预测试卷(附答案可下载)
- 2026年深圳中考物理高频考点精练试卷(附答案可下载)
- 光伏光热一体化项目合作协议
- 2026年广州中考政治让友谊之树常青试卷(附答案可下载)
- 校长赴深圳考察学习有感
- 人工智能在工业制造中的技术要领
- 万科施工管理办法
- 2025至2030中国养老健康行业深度发展研究与企业投资战略规划报告
- Roland罗兰乐器AerophoneAE-20电吹管ChineseAerophoneAE-20OwnersManual用户手册
- 2025年保安员资格考试题目及答案(共100题)
- 党群工作部室部管理制度
- 2025至2030年中国兔子养殖行业市场现状调查及投资方向研究报告
- 委外施工安全试题及答案
- DBT29-320-2025 天津市建筑工程消能减震隔震技术规程
- 产品技术维护与保养手册
- 2024年国家电网招聘之电工类考试题库(突破训练)
- 中建公司建筑机电设备安装工程标准化施工手册
评论
0/150
提交评论