第十二章C语言中用户标识符的.ppt

上传人:本田雅阁 文档编号:2122388 上传时间:2019-02-19 格式:PPT 页数:97 大小:393.51KB
返回 下载 相关 举报
第十二章C语言中用户标识符的.ppt_第1页
第1页 / 共97页
第十二章C语言中用户标识符的.ppt_第2页
第2页 / 共97页
第十二章C语言中用户标识符的.ppt_第3页
第3页 / 共97页
亲,该文档总共97页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《第十二章C语言中用户标识符的.ppt》由会员分享,可在线阅读,更多相关《第十二章C语言中用户标识符的.ppt(97页珍藏版)》请在三一文库上搜索。

1、1,第十二章C语言中用户标识符的作用域和存储类,知识点1:局部变量与全局变量 1.局部变量又称内部变量。全局变量又称外部变量。 2.在函数内部或复合语句内部定义的变量称局部变量,形参也是局部变量,其作用域从定义的位置开始到本函数或本复合语句结束。 3.在函数外部定义的变量称全局变量,其作用域从定义的位置开始到本源文件结束。 4.在同一个源文件中不同函数中的局部变量可以同名,不同复合语句中的局部变量可以同名。,2,5.在同一个源文件中,全局变量可以和局部变量同名,局部变量将屏蔽同名全局变量。 6.在函数体外进行的函数原型说明也使该函数具有全局的性质,其有效范围是从说明处起到源文件结束。 例如:

2、int a; int f(int x,int y) int j; j=a; main() int x,y; x=a; ,3,知识点2:变量的存储类别 1.C语言中,有两种存储类别:一种是自动类,一种是静态类。 2.局部变量既可以说明成自动类,也可以说明成静态类。全局变量只能是静态类。 3.存储类别有关的说明符:auto(自动)、register(寄存器)、static(静态)和extern(外部)。 4.存储类别说明符的说明形式:通常与类型名一起出现,可以放在类型名左边或右边。 例如:auto int i,j; 也可写成 int auto i,j;,4,知识点3:局部变量及其作用域和生存期 1

3、.auto变量 当在函数内部或复合语句内定义变量时,如果没有指定存储类或使用了auto说明符,系统就认为所定义的变量具有自动类别。因此, float a;等价于 auto float a; auto变量的存储单元被分配在内存的动态存储区。每当进入函数体(或复合语句)时,系统自动为auto变量分配存储单元。退出时自动释放这些存储单元。因此,这类局部变量的作用域是从定义的位置起,到函数体(或复合语句)结束为止。,5,例如: sub(float a) int i; if(i0) int n; printf(“%dn”,n); 这里,变量i,a,n都是auto变量。但i和a的作用域是整个sub函数;而

4、n的作用域仅限于if子名内。,6,生存期:所有自动类局部变量的存储单元都是在进入这些局部变量所在的函数体(或复合语句)时生成,退出其所在的函数体(或复合语句)时消失。 2.register变量 寄存器变量也是自动类变量。它与auto变量的区别仅在于:用register变量是将变量的值保留在CPU的寄存器中,而不是象一般变量那样,占内存单元。特点:程序运行速度快,因为访问寄存器比访问内存快。 注意:(1)CPU中寄存器的数目有限,只能说明少量寄存器变量。 (2)register变量的值存放在寄存器中,因此不能对register变量进行求地址运算。,7,例:以下函数power用以计算xn main

5、() int s; s=power(5,3); printf(“%dn”,s); power(int x, register int n) register int p; for(p=1; n;n-) p=p*x; return p;,8,3.静态存储类的 当在函数体(或复合语句)内部,用static来说明一个变量时,可以称该变量为静态局部变量。静态局部变量作用域与auto,register类的变量一样。 区别(1)在整个程序运行期间,静态局部变量在内存的静态存储区中占所着永久性的存储单元。即使退出函数以后,下次再进入该函数时,静态局部变量仍使用原来的存储单元。由于并不释放这些存储单元,因此这

6、些存储单元中的值得以保留,由此可知,静态局部变量的生存期将一直延长到程序运行结束。,9,(2)静态局部变量的初值是在编译时赋予的,在程序执行期间不再赋予初值。对未赋初值的静态局部变量,C编译程序自动给它赋初值0. 例:以下程序输出结果 int x=3; main() int i; for(i=1;ix;i+) incre(); int incre() static int x=1; x*=x+1; printf(“ %d”,x); A.3 3 B.2 2 C.2 6 D.2 5,10,知识点4:全局变量及其作用域和生存期 全局变量只有静态一种类别。对于全局变量可使用extern和static两

7、种说明符。 1.全局变量的作用域和生存期 全局变量是在函数外部任意位置上定义的变量,它的作用域是从变量定义的位置开始,到整个源文件结束止。例如: int sum; main( ) sum+; int fun1() sum+; int test; int fun2() sum+;test=1;,11,全局变量的生存期是整个程序的运行期间。若全局变量和某一函数中的局部变量同名,则在该函数中,此全局变量被屏蔽,在该函数内访问的是局部变量。 例:有以下程序 int a=3; main() int s=0; int a=5;s+=a+; s+=a+; printf(“%dn”,s); 程序运结果 A.

8、8 B.10 C. 7 D.11,12,2.在同一编译单位内用extern说明符来扩展全局变量的作用域。 当全局变量定义在后,引用它的函数在前时,应该在引用它的函数中用extern对此全局变量进行说明,以便通知编译程序:该变量是一个已在外部定义了的全局变量,这时其作用域从extern说明处起,延伸到该函数末尾。 fun1() extern int x; fun2() int a; a=x; int x,y; main() x=2; ,13,3.静态全局变量 当用static说明符说明全局变量时,此变量可称作“静态”全局变量。静态全局变量只限于本编译单位使用,不能被其它编译单位所引用。 例: /

9、*file1.c*/ /*file2.c*/ static int n; extern int n; void func(); void func() main() printf(“%file2:%dn”,); n=5; printf(“file1:%dn”,n); func(); ,14,知识点5:函数的类别 所有函数都是外部的,因为不允许在函数内部定义另一个函数。但当定义函数时,可以使用extern或static说明符。 1.一般的函数都隐含说明符extern.此说明的特征是:可以被其他编译单位中的函数调用。 2.若在函数返回值的类型前加上说明符static,则称此函数为“静态”函数。此类

10、函数的特征是:只限于本编译单位的其他函数调用它,而不允许其他编译单位中的调用它。,15,12-1以下程序的输出结果 main() int i=2,j=3; printf(“%d,”,i+); int i=0; i+=j*2; printf(“%d,%d,”,i,j); printf(“%d,%dn”,i,j); A.1,6,3,1,3 B.1,6,3,2,3 C.1,6,3,6,3 D.1,7,3,2,3,16,12-2以下程序的输出结果是 int m=13; int fun2(int x,int y) int m=3; return(x*y-m); main() int a=7,b=5; p

11、rintf(“%dn”,fun2(a,b)/m); A. 1 B.2 C.7 D.10,17,第十三章编译预处理和动态存储分配,在C语言中,凡是以”#“号开头的行,都称为“编译预处理”命令行。在此之前我们常用的由#include,#define开始的程序行就是编译预处理命令行。C语言预处理命令有:#undef,#if,#else等等。这些预处理命令组成的预处理命令行必须在一行的开头以“#”号开始,每行的末尾不得加“;”。,18,知识点1:不带参数的宏定义 1.不带参数的宏定义命令行形式如下: #define 宏名 替换文本 或#define 宏名 例:#define PI 3.14156 对于

12、以上例举的宏名PI,在编译时将把一串文本3.15156去替换源程序中的PI。 (1)同一宏名不可重复定义。 (2)替换文本不能替换双引号中与宏名相同的字符串。例如,如果YES是已定义的宏名,则不能用与它相关的替换文本来替换printf(“YES”)中的YES.,19,(3)替换文本并不替换用户标识符中的成分。例如,宏名YES,不会替换标识符YESORNO中的YES。 (4)用作宏名的标识符通常用大写字母表示,这并不是语法规定,只是一种习惯。 (5)在C程序中,宏定义的定义位置一般写在程序的开头。,20,知识点2:带参数的宏定义 1.带参数的宏定义命令行形式如下: #define 宏名(形参表)

13、 替换文本 例: #define MU(X,Y) (X)*(Y) a=MU(5,2); b=6/MU(a+3,a); 等价于 a=(5)*(2); b=6/(a+3)*(a);,21,(1)宏名和左括号之间不得有空格,形参之间用逗号隔开,替换文本中通常应包含有形参。 (2)调用带参的宏时,括号中实参的个数应与形参的相同。编译时,编译预处理程序用“替换文本”来替换宏名,用对应实参不加任何改动地替换“替换文本”中的形参。 (3)宏调用和函数调用有相似之处,但宏调用由编译预处理程序完成的,没有计算过程。 (4)宏调用中,实参不能替换括在双引号中的形参。,22,知识点3:文件包含 1.文件包含命令可有

14、以下两种形式 #include “文件名” #include 2.文件包含命令行的作用 预编译时,预编译程序将用指定文件中的内容来替换此命令行。如果文件名用双引号括起来,系统先在源程序所在的目录内查找指定的包含文件,如果找不到,再按照系统指定的标准方式到有关目录中去寻找。如果文件名用尖括号括起来,系统将直接按照系统指定的标准方式到有关目录中去寻找。,23,3.#include命令行应书写在所用文件的开头,因此也把包含文件称作“头文件”。头文件名可以由用户指定,其后缀不一定用“.h”。 4.包含文件中,一般包含有一些公用的#define命令行、外部说明或对(库)函数的原型说明。例如:“stdio

15、.h”就是这样的文件。 5.当包含文件修改后,对包含文件的源程序必须重新进行编译连接。 6.在一个程序中,允许有任意多个#include命令行。 7.在包含文件中还可以包含其他文件。,24,知识点4:动态存储分配 静态存储分配:我们用存储数据的变量和数组都必须在说明部分进行定义。C编译程序通过定义语句了解它们所需存储空间大小,并预先为其分配适当的内存空间。这些空间一经分配,在变量或数组的生存期内是固定不变的。 动态存储分配:在程序执行期间需要空间来存储数据时,通过“申请”分配指定的内存空间。 C为动态分配系统定义了四个函数,它们是malloc,calloc,free和realloc。使用这些函

16、数时,必须在程序开头包含头文件stdio.h。本书只介绍malloc,calloc和free函数的使用。,25,1.malloc函数 其函数原型为void * malloc(unsigned int); malloc函数返回值的类型为void *,函数调用形式为:malloc(size)。要求size的类型为unsigned int。 其作用是在内存的动态存储区中分配一个长度为size的连续空间。如果此函数未能成功地执行,则返回空指针(NULL)。 我们知道int型占2字节,float型占4字节,则以下程序段将使pi指向一个int类型的存储单元,使pf指向一个float类型的存储单元。,26,

17、int *pi; float *pf; pi=(int *)malloc(2); pf=(float *)malloc(4); 由于malloc函数返回的地址为void *(无值型),故在调用函数时,必须利用强制类型转换将其转换成所需的类型。此处括号中的*号不可少,否则就转换成普通变量类型而不是指针类型了。 若不能确定数据类型所占字节数,可以使用sizeof运算符来求得。例如: pi=(int *)malloc(sizeof(int); pf=(float *)malloc(sizeof(float);,27,2.free函数 其函数原型为void free(void *p); 函数调用形式为

18、:free(p);这里指针p必须指向由动态分配函数malloc分配的地址。free函数将指针p所指的存储空间释放,使这部分空间可以由系统重新支配。此函数没有返回值。 3.calloc函数 其函数原型为 void * calloc(unsigned n,unsigned size); 函数调用形式为:calloc(n,size); calloc函数用来给n个同一类型的数据项分配连续的存储空间。每个数据项的长度为size个字节。若分配成功,函数返回存储空间的首地址;否则返回空。由调用calloc函数所分配的存储单元,系统自动置初值0。,28,例如: char *ps; ps=(char *)cal

19、loc(10,sizeof(char); 以上函数调用语句开辟了10个连续的char类型的存储单元,由ps指向存储单元的首地址。每个存储单元可以存放一个字符。 使用calloc函数开辟的动态存储单元,同样用free函数释放。形式同malloc。,29,第十四章结构体、共用体和用户定义类型,目前为止,我们已经介绍了C语言中的基本类型(整型、字符型、实型、双精度型和空值型)以入派生类型(指针和数组)。本章将介绍C语言中可由用户构造的三种数据类型。 1.用户定义类型(typedef):对已有的类型,另外说明一个新的类型标识符。 2.结构体(struct):把具有相互关系的不同类型的数据组成一个有机的

20、整体。 3.共用体(union):又称联合体。使几种不同类型的变量共用一段存储空间。,30,知识点1:用typedef说明一种新类型名 用typedef说明一个新的类型标识符的一般形式如下: typedef 类型名 标识符; 在此,“类型名”必须是已有类型标识符,“标识符”是一个用户定义标识符,用作新的类型名。typedef语句的作用仅仅是用“标识符”来代表已存在的“类型名”,并未产生新的数据类型。原有类型名依然有效。例如: typedef int INTEGER; 该语句把一个用户命名的标识符INTEGER说明成了一个int类型的类型名。在此说明后,可以用INTEGER定义整型变量。如: I

21、NTEGER m,n;等价于 int m,n;,31,又如: typedef char * CHARP; CHARP p;等价于 char *p; 14-1若有以下说明和定义 typedef int * INTEGER; INTEGER p,*q; 以下叙述正确的是 A.p是int型变量 B.p是基类型为int的指针变量 C.q是基类型为int的指针变量 D.程序中可用INTEGER代替int类型名,32,14-2若要说明一个类型名STP,使得定义语句 STP s;等价于char *s;,以下选项中正确的是 A.typedef STP char *s; B.typedef *char STP;

22、 C.typedef STP *char; D.typedef char *STP;,33,知识点2:结构体类型 结构体类型由若干个称为成员的成分组成。对于 某个具体的结构体类型,成员的数量必须固定,这与数组相同;但该结构体中各个成员的类型可以不同,这与数组区别。 例如:我们常用的“日期”可由以下三部分描述:年(year),月(month),日(day)。可以把这三个成员组成一个整体,并给它取名为date,这就是一个简单的结构体。 再如:以学生档案为例,若包括如下数据项: 姓名(name):字符串;性别(sex):字符型 出生日期(birthday):date 结构体; 四门课成绩(sc):一

23、维实型数组;可将这四个成员组成一个名为student的结构体。,34,1.结构体类型说明的一般形式 struct 结构体标识名 类型名 结构成员名; ; (1)struct是关键字,是结构体类型的标志。 (2)结构体标识名是用户定义的标识符.可以省略,构成一个无名结构体类型。 (3)结构体成员名是用户定义标识符,可以与其他变量名和和其他结构体中的成员名同名。 (4)结构体成员可以是简单类型,数组,指针或已说明过的结构体等 (5)结构体类型说明最后分号不可省略。,35,例如:上述日期的结构体类型可以说明如下: struct date int year, month,day; 上述学生档案的结构体

24、类型可以说明如下: struct student char name12; char sex; struct date birthday; float sc4; ; 以上说明中,birthday成员的类型struct date是一个已说明过的结构体类型。,36,若没有事先说明这一类型,以上结构体类型说明可改写成如下形式: struct student char name12; char sex; struct int year; int month; int day; birthday; float sc4; ;,37,2.结构体类型的变量、数组和指针变量的定义 可以用以下四种方式定义结构体类

25、型的变量、数组和指针变量: (1)紧跟在结构体类型说明之后进行定义。例: struct student char name12; char sex; struct date birthday; float sc4; std,per3,*pstd; 此处在说明结构体类型struct student的同时,定义了一个结构体变量std,具有3个元素的结构体数组pers和基类型为结构体类型的指针变量pstd。,38,变量std的结构如图 具有这一结构类型的变量中只能存放一组数据(即一个学生的档案)。 如果要存放多个学生的数据,就要使用结构体类型的数组。以上定义的数组pers就要以存放三名学生的档案。它

26、每一个元素都是一个struct student类型的变量。 以上定义的指针变量pstd可以指向具有struct student类型的存储单元,但目前还没有具体的指向。,39,(2)在说明一个无名结构体类型的同时,直接进行定义。例如:以上定义的结构体中可以把student略去,写成: struct char name12; char sex; struct date birthday; float sc4; std,per3,*pstd; 这种方式与前一种的区别仅仅是省去了结构体标识名。,40,(3)先说明结构体类型,再单独进行变量定义。例如: struct student char name1

27、2; char sex; struct date birthday; float sc4; ; struct student std,per3,*pstd;,41,(4)使用typedef说明一个结构体类型名,再用新类型名来定义变量。例如: typedef struct char name12; char sex; struct date birthday; float sc4; STREC; STREC std,pers3,*pstd; 此处STREC是一个具体的结构体类型名。它能够唯一的标识这种结构体类型。因此,可用它来定义变量,如同使用int,char一样,不可再写关键字struct.,

28、42,3.给结构体变量、数组赋初值 (1)给结构体变量赋初值 所赋初值顺序放在一对花括号中,例如: struct student char name12; char sex; struct date birthday; float sc4; std=“Li Min”,”M”,1962,5,10,88,76,85,92;,43,赋初值后,变量std的内容如图 对结构体变量进行赋初值时,C编译程序按每个成员在结构体中的顺序一一对应赋初值;不允许跳过前边的成员给后面的成员赋初值;但可以只给前面的若干个成员赋初值,对于后面未赋初值的成员,对于数值型和字符型数据,系统自动赋初值零。,44,(2)给结构体

29、数组赋初值 给结构体数组赋初值的规则与给数组赋初值规则相同。只是由于结构体数组中的每个元素都是一个结构体,因此通常将其成员放在一对花括号中,以便区分各个元素.例如: struct bookcard char num; float money; bk3=“NO.1”,35.5,“NO.2”,38.0, “NO.3”,35.5;,45,4.引用结构体变量中的数据 (1)对结构成员的引用 若已定义了一个结构体变量,和基类型为同一结构体类型的指针变量,并使该指针指向同类型的变量,则可用以下三种形式来引用结构体变量中的成员。 结构体变量名.成员名 指针变量名-成员名 (*指针变量名).成员名 其中点号为

30、成员运算符;箭头为结构指向运算符;在第三种形式中,一对圆括号不可少。,46,例: struct student char name12; char sex; struct date birthday; float sc4; std,arr5,*ps; ps= 若要引用结构体变量std中的sex成员,可写作: std.sex 通过结构体变量引用 ps-sex 通过指针变量引用 (*ps).sex 通过指针变量引用,47,若要引用结构体数组arr的第0个元素arr0中的sex成员,可写作arr0.sex。不能写成arr.sex。 若要引用结构体变量std中数组成员sc中的元素sc2时,可写作std

31、.sc2或ps-sc2或(*ps).sc2或arr0.sc2。不能写成std.sc。 若结构体变量中的成员是作为字符串使用的字符型数组,如结构体中的成员name,由于可以将其看作“字符串变量”,因此其引用形式可以是std.name或ps-name或(*p).name或arr0.name.,48,内嵌结构体变量成员的引用 访问结构体变量中各内嵌结构体成员时,必须逐层使用成员名定位。例如:引用结构体变量std中的出生年份时,可写作std.birthday.year或ps-birthday.year或(*ps).birthday.year或arr0.birthday.year。注意birthday不

32、能用-运算符,因为birthday不是指针变量。. (2)对结构体变量中的成员进行操作 结构体变量中的每个成员都属某个具体的数据类型。因此,对结构体变量中的每个成员,都可以象普通变量一样,对它进行同类变量所允许的任何操作。例:变量std中的成员std.name是字符串型,可以对它进行任何字符串允许的操作。,49,若有定义: struct student std,pers5,*pstd; pstd=因为成员name为数组,不能直接用赋值语句赋字符串。,50,以下对相应变量中的sex成员进行操作: scanf(“%c”,51,以下对相应变量中成员数组sc中的元素进行操作 for(j=0;jscj)

33、; for(i=0;i3;i+) for(j=0;j5;j+) scanf(“%f”, ,52,与+,-运算符组成表达式时,应当根据运算符的优先级别来确定表达式的含义。例如: struct int a; char *s; x,*p= 其中变量x的成员a,指针成员s已正确赋值,则表达:+p-a等价于+(p-a)使得a增1,因为运算符-的优先级高于+。若要在访问a之前使p增1,应当写成(+p)-a或p+ -a。,53,相同类型结构体变量之间的整体赋值 struct char name10; int num; per1,per2=“YANGGM”,46; 执行语句:per1=per2;后,per2中

34、每个成员的值都赋给了per1中对应的同名成员。这种方法必须保证赋值号两边结构体变量的类型相同。,54,5.函数之间结构体变量的数据传递 (1)向函数传递结构体变量的成员 在前面指出:结构体变量中的每个成员可以是简单变量、数组或指针变量等,作为成员变量,它们可以参与所属类型允许的任何操作。这一原则在参数传递中仍适用。 (2)向函数传递结构体变量 结构体变量可作为实参将结构体变量的值传送给相应的形参。 (3)传递结构体的地址 将结构体变量的地址作为实参传递给形参,这时对应的形参应该是一个基类型相同的结构体类型的指针。,55,例:通过函数给结构体成员赋值 typedef struct cahr s1

35、0; int t; ST; getdata(ST *p) 形参为结构体类型的指针变量 scanf(“%s%d”,p-s, ,56,(4)函数的返回值是结构体类型 书上例14.2通过函数返回结构体类型的值。 (5)函数的返回值可以是指向结构体变量的指针类型。 书上例14.3、14.4,57,6.利用结构体变量构成链表 (1)链表概述 链表是一种常见的数据结构。它是动态地进行存储分配的一种结构。如图表示最简单的一种链表的结构. 链表有一个“头指针”变量,图中以head表示,它存放一个地址。该地址指向一元素。链表中每一个元素称为“结点”,每个结点都应包括两个部分:一为用户需要用的实际数据,二为下一个

36、结点的地址。可以看出,head指向第一个元素;第一个元素又指向第二个元素直到最后一个元素,称它为“表尾”,且地址部分为“NULL”。,58,可以看到链表中各元素在内存中可以不是连续存放的。要找某一元素,必须先找到上一个元素,根据它提供的下一元素地址才能找到下一个元素。如果不提供“头指针”(head),则整个链表都无法访问。 这种链表的数据结构,必须利用指针变量才能实现。即:一个结点中应包含一个指针变量,用于存放下一结点的地址。 前面介绿了结构体变量,用它作链表中的结点是最合适的。一个结构体变量包含若干成员,这些成员可以是数值类型、字符类型、数组类型,也可以是指针类型。我们用这个指针类型成员来存

37、放下一个结点的地址。例如:,59,struct student int num; float score; struct student *next; ; 其中成员num和score用来存放结点中的有用数据,相当于上图结点中的A,B,C,D。next是指针类型的成员,它指向struct student类型数据。一个指针类型的成员既可以指向其他类型的结构体数据,也可以指向自己所在结构体类型的数据。现在,next是struct student类型中的一个成员,它又指向struct student类型的数据。用这种方法就可以建立链表。,60,如果所示 图中每个结点都属于struct student类

38、型,它的成员next存放下一结点的地址,程序设计人员可以不必具体知道各结点的地址,只要保证将下一个结点的地址放到前一结点的成员next中即可。这种从当前结点找到后继结点的链表,称为“单向链表”。,61,例:建立一个如上图所的链表,它由4个学生数据的结点组成,并输出各结点中的数据。 #define NULL 0 struct student long num; float score; struct student *next; main() struct student a,b,c,d,*head,*p; a.num=99101;a.score=89.5; b.num=99103;b.scor

39、e=90; c.num=99105;c.score=85; d.num=99107;d.score=80; head=,62,(2)在单向链表中插入结点 在单链表中插入结点,首先要确定插入的位置。当插入结点插在指针p所的结点之前称为“前插”,当插入结点插在指针p所指的结点之后称为“后插”。如图所示“前插”操作过程中各指针的指向。 当进行“前插”操作时,需要三个工作指针:图中用s来指向新开辟的结点;用p指向插入的位置;q指向s的前趋结点。 s-next=p; q-next=s;,63,(3)删除单向链表中的结点 为了删除单向链表中的某个结点,首先要找到待删结点的前趋结点;然后将此前趋结点的指针去

40、指向待删结点的后续结点;最后释放被删结点所占存储空间即可。如图所示删除结点操作。 q-next=p-next;,64,知识点3:共用体 共用体的类型说明和变量的定义方式和结构体的类型说明和变量定义的方式完全相同,不同的是,结构体变量中的成员各自占有自己的存储空间,而共用体变量中的所有成员占有同一个存储空间。 1.共用体类型的说明和变量定义 (1)共用体类型的说明 一般形式: union 共用体名 类型名 共用体成员名; ;,65,例如: union un_1 int i; float x; char ch; ; 其中union是关键字,是共用体类型的标志。un_1是共用体名,“共用体名”和“共

41、用成员名”都是由用户定义的标识符,按语法规定,共用体名是可选项,在说明中可以不出现。共用体中的成员可能是简单变量,也可以是数组、指针、结构体和共用体(结构体的成员也可以是共用体)。,66,(2)共用体变量的定义 和结构体相似,共用体变量的定义也可以采用四种方式。取其一示例如下: union un_1 int i; float x; s1,s2,*p; 这里变量s1的存储空间如图所示,67,说明: 共用体类型变量的定义,在形式上与结构体非常相似,但它们是有本质区别的:结构体中的每个成员分别占有独立的存储空间,因此结构体变量所占内存字节数,是其成员所占字节数的总和;而共用体变量中的所有成员共享一段

42、公共存储区,所以共用体变量所占内存字节数与其成员中占字节数最多的那个成员相等。若int型占2字节,float型占4字节,则以上定义的共用体变量占4字节,而不是6字节。 由于共用体变量中的所有成员共享存储空间,因此变量中的所有成员的首地址相同,而且变量的地址也就是该变量成员的地址。例如:&s1=&s1.i=&s1.x。,68,2.共用体变量的引用 (1)共用体变量中成员的引用 共用体变量中每个成员的引用方式与结构体完全 相同。可以使用以下三种形式之一: 共用体变量名.成员名 指针变量名-成员名 (*指针变量名).成员名 例如:若s1,s2,p的定义如前,且有p=&s1:,则s1.i,s1.x,或

43、p-i,p-x,(*p).i,(*p).x都是合法的引用形式。 共用体中的成员变量同样可参与其所属类型允许的任何操作。但在访问共用体成员时应注意:共用体变量中起作用的是最近一次存入的成员变量的值,原有成员变量的值将被覆盖。,69,例如: union un_1 int i; int x; s1; main() s1.x=123; s1.i=100; printf(“%dn“,s1.x); ,70,(2)共用体变量的整体赋值 例如: s1.i=5; s2=s1; printf(“%dn”,s2.i); 输出的值为5. (3)向函数传递共用体变量的值 同结构体变量一样,共用体类型的变量可以作为实参进

44、行传递,也可以传送共用体变量的地址。 例如:利用共用体类型的特点分别取出int变量中高字节和低字节中的两个数。,71,union change char c2; int a; un; main() un.a=16961; printf(“%d,%cn”,un.c0,un.c0); printf(“%d,%cn”,un.c1,un.c1); 共用体变量un中包含两个成员:字符数组c和整数变量a,它们恰好都占两个字节的存储单元。由于是共用存储单元,给un的成员a赋值后,内存中数据的存储情况如图所示,72,当给成员un.a赋16961后,系统将按int整型把数存放到存储空间中:分别输出un.c1,u

45、n.c0即完成把一个int整型数分别按高字节和低字节输出。,73,第十五章位运算,知识点1:位运算符 1.位运算符及功能,74,知识点2:位运算符的运算功能 1.“按位取反”运算() 功能:是将把运算对象的内容按内容取反:即每一位上的0变1;1变0。例如:表达式0115是将八进制数115按位求反。由于是“位”运算,为了直观起见,我们把运算对象直接用二进制形式表示: 01001101 结果 10110010,75,2.“左移”运算() 左移运算符是双目运算符。运算符左边是移位对象;右边是整型表达式,代表左移的位数。左移时,右端(低位)补0;左端(高位)移出的部分舍弃。例如: char a=6,b

46、; b=a2; 用二进制数来表示运算过程如下: a:00000110 (a=6) b=a2:00011000,76,3.“右移”运算() 右移运算符使用方法与左移运算符一样,所不同的是移位方向相反。右移时,右端(低位)移出的二进制数舍弃;左端(高位)移入的二进制数分两种情况:对于无符号整数和正整数,高位补0;对于负整数,高位补1。这是因为负数在机器内均用补码表示。例如: int a=-714000,b; 用二进制数表示的运算过程如下: 符号位 a的二进制原码表示:11110011 00000000 a的二进制补码表示:10001101 00000000 b=a2 : 11100011 0100

47、0000(b的补码) b的二进制原码表示:10011100 11000000 b的八进制娄 :-016300,77,4.“按位与”运算(&) 运算符&的功能:把参加运算的两个运算数,按对应的二进制位分别进行“与”运算,当两个相应的位都为1时,该位的结果为1;否则为0.例如,表达式12&10的运算如下: 12:00001100 &10: 00001010 结果:00001000,78,5.“按位异或”运算() 异或运算的功能:参与运算的两个运算数中相对应的二进制位上,若数相同,则该位的结果为0;数不同,则该位的结果为1。例如: 00110011 11000011 结果:11110000,79,6

48、.“按位或”运算(|) 按位“或”运算功能:参加运算的两个运算数中,只要两个相应的二进制位中有一个为1,该位的运算结果即为1;只有当两个相应位的数都为0时,该位的运算结果才为0。例如: 0123:01010011 014:00001100 结果:01011111,80,第十六章文件,知识点1:文件指针 文件指针,实际上是指向一个结构体类型的指针变量;这个结构体中包含有诸如:缓冲区的地址、在缓冲区中当前存取的字符的位置、对文件是“读”还是“写”、是否已经遇到文件结束标志等信息。我们不必去了解其中的细节,所有一切都在stdio.h头文件中进行了定义;并称此结构体类型名为FILE,可以用此类型名来定义文件指针。定义文件类型指针变量的一般形式为: FILE *指针变量名; 例如: FILE *fp1,*fp2; fp1,fp2均被定义为指向文件类型的指针变量,称为文件指针。,81,知识点2:打开文件 1.fopen函数。用于打开文件。 (1)调用形式如下: FILE *fp; fp=fopen(文件名,文件使用方式); 例如:fp=fopen(“C:abc.dat”,”w”)

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1