C语言中用户标识符的

上传人:痛*** 文档编号:244592655 上传时间:2024-10-05 格式:PPT 页数:97 大小:391.50KB
返回 下载 相关 举报
C语言中用户标识符的_第1页
第1页 / 共97页
C语言中用户标识符的_第2页
第2页 / 共97页
C语言中用户标识符的_第3页
第3页 / 共97页
点击查看更多>>
资源描述
,*,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,第十二章,C,语言中用户标识符的作用域和存储类,知识点,1,:局部变量与全局变量,1.,局部变量又称内部变量。全局变量又称外部变量。,2.,在函数内部或复合语句内部定义的变量称局部变量,形参也是局部变量,其作用域从定义的位置开始到本函数或本复合语句结束。,3.,在函数外部定义的变量称全局变量,其作用域从定义的位置开始到本源文件结束。,4.,在同一个源文件中不同函数中的局部变量可以同名,不同复合语句中的局部变量可以同名。,1,5.,在同一个源文件中,全局变量可以和局部变量同名,局部变量将屏蔽同名全局变量。,6.,在函数体外进行的函数原型说明也使该函数具有全局的性质,其有效范围是从说明处起到源文件结束。,例如:,int a;,int f(int x,int y), int j; j=a;,main(),int x,y;,x=a;,2,知识点,2,:变量的存储类别,1.C,语言中,有两种存储类别:一种是自动类,一种是静态类。,2.,局部变量既可以说明成自动类,也可以说明成静态类。全局变量只能是静态类。,3.,存储类别有关的说明符:,auto(,自动,),、,register(,寄存器,),、,static(,静态,),和,extern(,外部,),。,4.,存储类别说明符的说明形式:通常与类型名一起出现,可以放在类型名左边或右边。,例如,:auto int i,j;,也可写成,int auto i,j;,3,知识点,3,:局部变量及其作用域和生存期,1.auto,变量,当在函数内部或复合语句内定义变量时,如果没有指定存储类或使用了,auto,说明符,系统就认为所定义的变量具有自动类别。因此,,float a;,等价于,auto float a;,auto,变量的存储单元被分配在内存的动态存储区。每当进入函数体,(,或复合语句,),时,系统自动为,auto,变量分配存储单元。退出时自动释放这些存储单元。因此,这类局部变量的作用域是从定义的位置起,到函数体,(,或复合语句,),结束为止。,4,例如:,sub(float a), int i;,if(i0), int n;,printf(,“,%dn,”,n);,这里,变量,i,a,n,都是,auto,变量。但,i,和,a,的作用域是整个,sub,函数;而,n,的作用域仅限于,if,子名内。,5,生存期:所有自动类局部变量的存储单元都是在进入这些局部变量所在的函数体(或复合语句)时生成,退出其所在的函数体(或复合语句)时消失。,2.register,变量,寄存器变量也是自动类变量。它与,auto,变量的区别仅在于:用,register,变量是将变量的值保留在,CPU,的寄存器中,而不是象一般变量那样,占内存单元。特点:程序运行速度快,因为访问寄存器比访问内存快。,注意:,(1)CPU,中寄存器的数目有限,只能说明少量寄存器变量。,(,2,),register,变量的值存放在寄存器中,因此不能对,register,变量进行求地址运算。,6,例:以下函数,power,用以计算,x,n,main(), 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;,7,3.,静态存储类的,当在函数体(或复合语句)内部,用,static,来说明一个变量时,可以称该变量为静态局部变量。静态局部变量作用域与,auto,register,类的变量一样。,区别,(,1,)在整个程序运行期间,静态局部变量在内存的静态存储区中占所着永久性的存储单元。即使退出函数以后,下次再进入该函数时,静态局部变量仍使用原来的存储单元。由于并不释放这些存储单元,因此这些存储单元中的值得以保留,由此可知,静态局部变量的生存期将一直延长到程序运行结束。,8,(,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 3B.2 2C.2 6D.2 5,9,知识点,4,:全局变量及其作用域和生存期,全局变量只有静态一种类别。对于全局变量可使用,extern,和,static,两种说明符。,1.,全局变量的作用域和生存期,全局变量是在函数外部任意位置上定义的变量,它的作用域是从变量定义的位置开始,到整个源文件结束止。例如:,int sum;,main( ), sum+;,int fun1(), sum+;,int test;,int fun2(), sum+;test=1;,10,全局变量的生存期是整个程序的运行期间。若全局变量和某一函数中的局部变量同名,则在该函数中,此全局变量被屏蔽,在该函数内访问的是局部变量。,例:有以下程序,int a=3;,main(),int s=0;,int a=5;s+=a+;,s+=a+; printf(“%dn”,s);,程序运结果,A. 8B.10C. 7D.11,11,2.,在同一编译单位内用,extern,说明符来扩展全局变量的作用域。,当全局变量定义在后,引用它的函数在前时,应该在引用它的函数中用,extern,对此全局变量进行说明,以便通知编译程序:该变量是一个已在外部定义了的全局变量,这时其作用域从,extern,说明处起,延伸到该函数末尾。,fun1(), ,extern int x;,fun2(), int a; a=x; ,int x,y;,main(), x=2; ,12,3.,静态全局变量,当用,static,说明符说明全局变量时,此变量可称作“静态”全局变量。,静态全局变量只限于本编译单位使用,不能被其它编译单位所引用。,例:,/*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();,13,知识点,5,:函数的类别,所有函数都是外部的,因为不允许在函数内部定义另一个函数。但当定义函数时,可以使用,extern,或,static,说明符。,1.,一般的函数都隐含说明符,extern.,此说明的特征是:可以被其他编译单位中的函数调用。,2.,若在函数返回值的类型前加上说明符,static,,则称此函数为“静态”函数。此类函数的特征是:只限于本编译单位的其他函数调用它,而不允许其他编译单位中的调用它。,14,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,15,12-2,以下程序的输出结果是,int m=13;,int fun2(int x,int y), int m=3;,return(x*y-m);,main(), int a=7,b=5;,printf(“%dn”,fun2(a,b)/m);,A. 1B.2C.7D.10,16,第十三章编译预处理和动态存储分配,在,C,语言中,凡是以”,#“,号开头的行,都称为“编译预处理”命令行。在此之前我们常用的由,#include,#define,开始的程序行就是编译预处理命令行。,C,语言预处理命令有:,#undef,#if,#else,等等。这些预处理命令组成的预处理命令行必须在一行的开头以“,#”,号开始,每行的末尾,不得加“;”,。,17,知识点,1,:不带参数的宏定义,1.,不带参数的宏定义命令行形式如下:,#define,宏名替换文本,或,#define,宏名,例:,#define PI 3.14156,对于以上例举的宏名,PI,,在编译时将把一串文本,3.15156,去替换源程序中的,PI,。,(,1,)同一宏名不可重复定义。,(,2,)替换文本不能替换双引号中与宏名相同的字符串。例如,如果,YES,是已定义的宏名,则不能用与它相关的替换文本来替换,printf(“YES”),中的,YES.,18,(3),替换文本并不替换用户标识符中的成分。例如,宏名,YES,,不会替换标识符,YESORNO,中的,YES,。,(,4,)用作宏名的标识符通常用大写字母表示,这并不是语法规定,只是一种习惯。,(,5,)在,C,程序中,宏定义的定义位置一般写在程序的开头。,19,知识点,2,:带参数的宏定义,1.,带参数的宏定义命令行形式如下:,#define,宏名(形参表) 替换文本,例:,#define MU(X,Y) (X)*(Y),a=MU(5,2);,b=6/MU(a+3,a);,等价于,a=(5)*(2);,b=6/(a+3)*(a);,20,(1),宏名和左括号之间不得有空格,形参之间用逗号隔开,替换文本中通常应包含有形参。,(,2,)调用带参的宏时,括号中实参的个数应与形参的相同。编译时,编译预处理程序用“替换文本”来替换宏名,用对应实参不加任何改动地替换“替换文本”中的形参。,(3),宏调用和函数调用有相似之处,但宏调用由编译预处理程序完成的,没有计算过程。,(,4,)宏调用中,实参不能替换括在双引号中的形参。,21,知识点,3,:文件包含,1.,文件包含命令可有以下两种形式,#include “,文件名”,#include ,2.,文件包含命令行的作用,预编译时,预编译程序将用指定文件中的内容来替换此命令行。如果文件名用双引号括起来,系统先在源程序所在的目录内查找指定的包含文件,如果找不到,再按照系统指定的标准方式到有关目录中去寻找。如果文件名用尖括号括起来,系统将直接按照系统指定的标准方式到有关目录中去寻找。,22,3.#include,命令行应书写在所用文件的开头,因此也把包含文件称作“头文件”。头文件名可以由用户指定,其后缀不一定用“,.h”,。,4.,包含文件中,一般包含有一些公用的,#define,命令行、外部说明或对(库)函数的原型说明。例如:“,stdio.h”,就是这样的文件。,5.,当包含文件修改后,对包含文件的源程序必须重新进行编译连接。,6.,在一个程序中,允许有任意多个,#include,命令行。,7.,在包含文件中还可以包含其他文件。,23,知识点,4,:动态存储分配,静态存储分配:我们用存储数据的变量和数组都必须在说明部分进行定义。,C,编译程序通过定义语句了解它们所需存储空间大小,并预先为其分配适当的内存空间。这些空间一经分配,在变量或数组的生存期内是固定不变的。,动态存储分配,:,在,程序执行期间,需要空间来存储数据时,通过“申请”分配指定的内存空间。,C,为动态分配系统定义了四个函数,它们是,malloc,calloc,free,和,realloc,。使用这些函数时,必须在程序开头包含头文件,stdio.h,。本书只介绍,malloc,calloc,和,free,函数的使用。,24,1.malloc,函数,其函数原型为,void * malloc(unsigned int);,malloc,函数返回值的类型为,void *,函数调用形式为:,malloc(size),。要求,size,的类型为,unsigned int,。,其作用是在内存的动态存储区中分配一个长度为,size,的连续空间。如果此函数未能成功地执行,则返回空指针(,NULL,)。,我们知道,int,型占,2,字节,,float,型占,4,字节,则以下程序段将使,pi,指向一个,int,类型的存储单元,使,pf,指向一个,float,类型的存储单元。,25,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);,26,2.free,函数,其函数原型为,void free(void *p);,函数调用形式为:,free(p);,这里指针,p,必须指向由动态分配函数,malloc,分配的地址。,free,函数将指针,p,所指的存储空间释放,使这部分空间可以由系统重新支配。此函数没有返回值。,3.calloc,函数,其函数原型为,void * calloc(unsigned n,unsigned size);,函数调用形式为:,calloc(n,size);,calloc,函数用来给,n,个同一类型的数据项分配连续的存储空间。每个数据项的长度为,size,个字节。若分配成功,函数返回存储空间的首地址;否则返回空。由调用,calloc,函数所分配的存储单元,系统自动置初值,0,。,27,例如:,char *ps;,ps=(char *)calloc(10,sizeof(char);,以上函数调用语句开辟了,10,个连续的,char,类型的存储单元,由,ps,指向存储单元的首地址。每个存储单元可以存放一个字符。,使用,calloc,函数开辟的动态存储单元,同样用,free,函数释放。形式同,malloc,。,28,第十四章结构体、共用体和用户定义类型,目前为止,我们已经介绍了,C,语言中的基本类型(整型、字符型、实型、双精度型和空值型)以入派生类型(指针和数组)。本章将介绍,C,语言中可由用户构造的三种数据类型。,1.,用户定义类型(,typedef,),:,对已有的类型,另外说明一个新的类型标识符。,2.,结构体,(struct):,把具有相互关系的不同类型的数据组成一个有机的整体。,3.,共用体,(union):,又称联合体。使几种不同类型的变量共用一段存储空间。,29,知识点,1,:用,typedef,说明一种新类型名,用,typedef,说明一个新的类型标识符的一般形式如下:,typedef,类型名 标识符;,在此,“类型名”必须是已有类型标识符,“标识符”是一个用户定义标识符,用作新的类型名。,typedef,语句的作用仅仅是用“标识符”来代表已存在的“类型名”,并未产生新的数据类型。原有类型名依然有效。例如:,typedef int INTEGER;,该语句把一个用户命名的标识符,INTEGER,说明成了一个,int,类型的类型名。在此说明后,可以用,INTEGER,定义整型变量。如:,INTEGER m,n;,等价于,int m,n;,30,又如:,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,类型名,31,14-2,若要说明一个类型名,STP,,使得定义语句,STP s;,等价于,char *s;,,以下选项中正确的是,A.typedef STP char *s;,B.typedef *char STP;,C.typedef STP *char;,D.typedef char *STP;,32,知识点,2,:结构体类型,结构体类型由若干个称为成员的成分组成。对于 某个具体的结构体类型,成员的数量必须固定,这与数组相同;但该结构体中各个成员的类型可以不同,这与数组区别。,例如:我们常用的“日期”可由以下三部分描述:年,(year),,月,(month),日,(day),。可以把这三个成员组成一个整体,并给它取名为,date,,这就是一个简单的结构体。,再如:以学生档案为例,若包括如下数据项:,姓名,(name):,字符串;性别,(sex):,字符型,出生日期,(birthday):date,结构体;,四门课成绩(,sc,),:,一维实型数组;可将这四个成员组成一个名为,student,的结构体。,33,1.,结构体类型说明的一般形式,struct,结构体标识名,类型名,结构成员名;,;,(,1,),struct,是关键字,是结构体类型的标志。,(,2,)结构体标识名是用户定义的标识符,.,可以省略,构成一个无名结构体类型。,(,3,)结构体成员名是用户定义标识符,可以与其他变量名和和其他结构体中的成员名同名。,(,4,)结构体成员可以是简单类型,数组,指针或已说明过的结构体等,(,5,)结构体类型说明最后,分号,不可省略。,34,例如:上述日期的结构体类型可以说明如下:,struct date, int year, month,day;,上述学生档案的结构体类型可以说明如下:,struct student, char name12;,char sex;,struct date birthday;,float sc4;,;,以上说明中,,birthday,成员的类型,struct date,是一个已说明过的结构体类型。,35,若没有事先说明这一类型,以上结构体类型说明可改写成如下形式:,struct student, char name12;,char sex;,struct, int year;,int month;,int day; birthday;,float sc4;,;,36,2.,结构体类型的变量、数组和指针变量的定义,可以用以下四种方式定义结构体类型的变量、数组和指针变量:,(,1,)紧跟在结构体类型说明之后进行定义。例:,struct student, char name12;,char sex;,struct date birthday;,float sc4;, std,per3,*pstd;,此处在说明结构体类型,struct student,的同时,定义了一个结构体变量,std,具有,3,个元素的结构体数组,pers,和基类型为结构体类型的指针变量,pstd,。,37,变量,std,的结构如图,具有这一结构类型的变量中只能存放一组数据(即一个学生的档案)。,如果要存放多个学生的数据,就要使用结构体类型的数组。以上定义的数组,pers,就要以存放三名学生的档案。它每一个元素都是一个,struct student,类型的变量。,以上定义的指针变量,pstd,可以指向具有,struct student,类型的存储单元,但目前还没有具体的指向。,38,(,2,)在说明一个无名结构体类型的同时,直接进行定义。例如:以上定义的结构体中可以把,student,略去,写成:,struct, char name12;,char sex;,struct date birthday;,float sc4;, std,per3,*pstd;,这种方式与前一种的区别仅仅是省去了结构体标识名。,39,(,3,)先说明结构体类型,再单独进行变量定义。例如:,struct student, char name12;,char sex;,struct date birthday;,float sc4;,;,struct student,std,per3,*pstd;,40,(4),使用,typedef,说明一个结构体类型名,再用新类型名来定义变量。例如:,typedef struct, char name12;,char sex;,struct date birthday;,float sc4;,STREC;,STREC std,pers3,*pstd;,此处,STREC,是一个具体的结构体类型名。它能够唯一的标识这种结构体类型。因此,可用它来定义变量,如同使用,int,char,一样,不可再写关键字,struct.,41,3.,给结构体变量、数组赋初值,(,1,)给结构体变量赋初值,所赋初值顺序放在一对花括号中,例如:,struct student, char name12;,char sex;,struct date birthday;,float sc4;,std=“Li Min”,”M”,1962,5,10,88,76,85,92;,42,赋初值后,变量,std,的内容如图,对结构体变量进行赋初值时,,C,编译程序按每个成员在结构体中的顺序一一对应赋初值;不允许跳过前边的成员给后面的成员赋初值;但可以只给前面的若干个成员赋初值,对于后面未赋初值的成员,对于数值型和字符型数据,系统自动赋初值零。,43,(,2,)给结构体数组赋初值,给结构体数组赋初值的规则与给数组赋初值规则相同。只是由于结构体数组中的每个元素都是一个结构体,因此通常将其成员放在一对花括号中,以便区分各个元素,.,例如:,struct bookcard, char num,;,float money;,bk3=“NO.1”,35.5,“NO.2”,38.0, “NO.3”,35.5;,44,4.,引用结构体变量中的数据,(,1,)对结构成员的引用,若已定义了一个结构体变量,和基类型为同一结构体类型的指针变量,并使该指针指向同类型的变量,则可用以下三种形式来引用结构体变量中的成员。,结构体变量名,.,成员名,指针变量名,-,成员名,(*,指针变量名,).,成员名,其中点号为成员运算符;箭头为结构指向运算符;在第三种形式中,一对圆括号不可少。,45,例:,struct student, char name12;,char sex;,struct date birthday;,float sc4;,std,arr5,*ps;,ps=,若要引用结构体变量,std,中的,sex,成员,可写作,:,std.sex,通过结构体变量引用,ps-sex,通过指针变量引用,(*ps).sex,通过指针变量引用,46,若要引用结构体数组,arr,的第,0,个元素,arr0,中的,sex,成员,可写作,arr0.sex,。不能写成,arr.sex,。,若要引用结构体变量,std,中数组成员,sc,中的元素,sc2,时,可写作,std.sc2,或,ps-sc2,或,(*ps).sc2,或,arr0.sc2,。不能写成,std.sc,。,若结构体变量中的成员是作为字符串使用的字符型数组,如结构体中的成员,name,,由于可以将其看作“字符串变量”,因此其引用形式可以是,std.name,或,ps-name,或,(*p).name,或,arr0.name.,47,内嵌结构体变量成员的引用,访问结构体变量中各内嵌结构体成员时,必须逐层使用成员名定位。例如:引用结构体变量,std,中的出生年份时,可写作,std.birthday.year,或,ps-birthday.year,或,(*ps).birthday.year,或,arr0.birthday.year,。注意,birthday,不能用,-,运算符,因为,birthday,不是指针变量。,.,(,2,)对结构体变量中的成员进行操作,结构体变量中的每个成员都属某个具体的数据类型。因此,对结构体变量中的每个成员,都可以象普通变量一样,对它进行同类变量所允许的任何操作。例:变量,std,中的成员,std.name,是字符串型,可以对它进行任何字符串允许的操作。,48,若有定义:,struct student std,pers5,*pstd;,pstd=,以下对相应变量中的,name,成员所进行的操作合法。,scanf(“%s”,std.name);,或,gets(std.name);,scanf(“%s”,pstd-name);,或,gets(pstd-name);,for(i=0;isex=getchar();,for(i=0;i3;i+) scanf(“%c”,std.sex=M;,以下对相应变量中,birthday,成员中,year,进行操作,scanf(“%d”,scanf(“%d”,for(i=0;i3;i+) scanf(“%d”,std.birthday.year=1962;,50,以下对相应变量中成员数组,sc,中的元素进行操作,for(j=0;j5;j+) scanf(“%f”,for(j=0;jscj);,for(i=0;i3;i+),for(j=0;ja,等价于,+(p-a),使得,a,增,1,,,因为运算符,-,的优先级高于,+,。,若要在访问,a,之前使,p,增,1,,应当写成,(+p)-a,或,p+ -a,。,52,相同类型结构体变量之间的整体赋值,struct, char name10;,int num;,per1,per2=“YANGGM”,46;,执行语句:,per1=per2;,后,,per2,中每个成员的值都赋给了,per1,中对应的同名成员。这种方法必须保证赋值号两边结构体变量的类型相同。,53,5.,函数之间结构体变量的数据传递,(1),向函数传递结构体变量的成员,在前面指出:结构体变量中的每个成员可以是简单变量、数组或指针变量等,作为成员变量,它们可以参与所属类型允许的任何操作。这一原则在参数传递中仍适用。,(2),向函数传递结构体变量,结构体变量可作为实参将结构体变量的值传送给相应的形参。,(3),传递结构体的地址,将结构体变量的地址作为实参传递给形参,这时对应的形参应该是一个基类型相同的结构体类型的指针。,54,例:通过函数给结构体成员赋值,typedef struct, cahr s10;,int t;,ST;,getdata(ST *p),形参为结构体类型的指针变量, scanf(“%s%d”,p-s,main(), ST a;,getdata(,结构体变量的地址作实参,printf(“%s,%dn”,a.s,a.t);,55,(,4,)函数的返回值是结构体类型,书上例,14.2,通过函数返回结构体类型的值。,(,5,)函数的返回值可以是指向结构体变量的指针类型。,书上例,14.3,、,14.4,56,6.,利用结构体变量构成链表,(,1,)链表概述,链表是一种常见的数据结构。它是动态地进行存储分配的一种结构。如图表示最简单的一种链表的结构,.,链表有一个“头指针”变量,图中以,head,表示,它存放一个地址。该地址指向一元素。链表中每一个元素称为“结点”,每个结点都应包括两个部分:一为用户需要用的实际数据,二为下一个结点的地址。可以看出,,head,指向第一个元素;第一个元素又指向第二个元素,直到最后一个元素,称它为“表尾”,且地址部分为“,NULL”,。,57,可以看到链表中各元素在内存中可以不是连续存放的。要找某一元素,必须先找到上一个元素,根据它提供的下一元素地址才能找到下一个元素。如果不提供“头指针”,(head),,则整个链表都无法访问。,这种链表的数据结构,必须利用指针变量才能实现。即:一个结点中应包含一个指针变量,用于存放下一结点的地址。,前面介绿了结构体变量,用它作链表中的结点是最合适的。一个结构体变量包含若干成员,这些成员可以是数值类型、字符类型、数组类型,也可以是指针类型。我们用这个指针类型成员来存放下一个结点的地址。例如:,58,struct student, int num;,float score;,struct student *next;,;,其中成员,num,和,score,用来存放结点中的有用数据,相当于上图结点中的,A,B,C,D,。,next,是指针类型的成员,它指向,struct student,类型数据。一个指针类型的成员既可以指向其他类型的结构体数据,也可以指向自己所在结构体类型的数据。现在,,next,是,struct student,类型中的一个成员,它又指向,struct student,类型的数据。,用这种方法就可以建立链表。,59,如果所示,图中每个结点都属于,struct student,类型,它的成员,next,存放下一结点的地址,程序设计人员可以不必具体知道各结点的地址,只要保证将下一个结点的地址放到前一结点的成员,next,中即可。这种从当前结点找到后继结点的链表,称为“单向链表”。,60,例:建立一个如上图所的链表,它由,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.score=90;,c.num=99105;c.score=85; d.num=99107;d.score=80;,head=,p=head;,do,printf(“%ld,%5.1fn”,p-num,p-score);,p=p-next; while (p!=NULL);,61,(2),在单向链表中插入结点,在单链表中插入结点,首先要确定插入的位置。当插入结点插在指针,p,所的结点之前称为“前插”,当插入结点插在指针,p,所指的结点之后称为“后插”。如图所示“前插”操作过程中各指针的指向。,当进行“前插”操作时,需要三个工作指针:图中用,s,来指向新开辟的结点;用,p,指向插入的位置;,q,指向,s,的前趋结点。,s-next=p; q-next=s;,62,(3),删除单向链表中的结点,为了删除单向链表中的某个结点,首先要找到待删结点的前趋结点;然后将此前趋结点的指针去指向待删结点的后续结点;最后释放被删结点所占存储空间即可。如图所示删除结点操作。,q-next=p-next;,63,知识点,3,:共用体,共用体的类型说明和变量的定义方式和结构体的类型说明和变量定义的方式完全相同,不同的是,结构体变量中的成员各自占有自己的存储空间,而共用体变量中的所有成员占有同一个存储空间。,1.,共用体类型的说明和变量定义,(,1,)共用体类型的说明,一般形式:,union,共用体名,类型名 共用体成员名;,;,64,例如:,union un_1, int i;,float x;,char ch;,;,其中,union,是关键字,是共用体类型的标志。,un_1,是共用体名,“共用体名”和“共用成员名”都是由用户定义的标识符,按语法规定,共用体名是可选项,在说明中可以不出现。共用体中的成员可能是简单变量,也可以是数组、指针、结构体和共用体(结构体的成员也可以是共用体)。,65,(,2,)共用体变量的定义,和结构体相似,共用体变量的定义也可以采用四种方式。取其一示例如下:,union un_1, int i;,float x;,s1,s2,*p;,这里变量,s1,的存储空间如图所示,66,说明:,共用体类型变量的定义,在形式上与结构体非常相似,但它们是有本质区别的:结构体中的每个成员分别占有独立的存储空间,因此结构体变量所占内存字节数,是其成员所占字节数的总和;而共用体变量中的所有成员共享一段公共存储区,所以共用体变量所占内存字节数与其成员中占字节数最多的那个成员相等。若,int,型占,2,字节,,float,型占,4,字节,则以上定义的共用体变量占,4,字节,而不是,6,字节。,由于共用体变量中的所有成员共享存储空间,因此变量中的所有成员的首地址相同,而且变量的地址也就是该变量成员的地址。例如,:&s1=&s1.i=&s1.x,。,67,2.,共用体变量的引用,(,1,)共用体变量中成员的引用,共用体变量中每个成员的引用方式与结构体完全 相同。可以使用以下三种形式之一:,共用体变量名,.,成员名,指针变量名,-,成员名,(*指针变量名),.,成员名,例如:若,s1,s2,p,的定义如前,且有,p=&s1:,则,s1.i,s1.x,或,p-i,p-x,(*p).i,(*p).x,都是合法的引用形式。,共用体中的成员变量同样可参与其所属类型允许的任何操作。但在访问共用体成员时应注意:共用体变量中起作用的是最近一次存入的成员变量的值,原有成员变量的值将被覆盖。,68,例如:,union un_1, int i;,int x;,s1;,main(),s1.x=123;,s1.i=100;,printf(%dn,s1.x);,69,(2),共用体变量的整体赋值,例如:,s1.i=5;,s2=s1;,printf(“%dn”,s2.i);,输出的值为,5.,(3),向函数传递共用体变量的值,同结构体变量一样,共用体类型的变量可以作为实参进行传递,也可以传送共用体变量的地址。,例如:利用共用体类型的特点分别取出,int,变量中高字节和低字节中的两个数。,70,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,赋值后,内存中数据的存储情况如图所示,71,当给成员,un.a,赋,16961,后,系统将按,int,整型把数存放到存储空间中:分别输出,un.c1,un.c0,即完成把一个,int,整型数分别按高字节和低字节输出。,72,第十五章位运算,知识点,1,:位运算符,1.,位运算符及功能,运算符,含义,优先级,按位求反,1,右移,2,&,按位与,3,按位异或,4,|,按位或,5,73,知识点,2,:位运算符的运算功能,1.“,按位取反”运算(,),功能:是将把运算对象的内容按内容取反:即每一位上的,0,变,1,;,1,变,0,。例如:表达式,0115,是将八进制数,115,按位求反。由于是“位”运算,为了直观起见,我们把运算对象直接用二进制形式表示:,01001101,结果,10110010,74,2.“,左移”运算,(),左移运算符是双目运算符。运算符左边是移位对象;右边是整型表达式,代表左移的位数。左移时,右端(低位)补,0,;左端(高位)移出的部分舍弃。例如:,char a=6,b;,b=a2;,用二进制数来表示运算过程如下:,a:00000110 (a=6),b=a,),右移运算符使用方法与左移运算符一样,所不同的是移位方向相反。右移时,右端(低位)移出的二进制数舍弃;左端(高位)移入的二进制数分两种情况:对于无符号整数和正整数,高位补,0,;对于负整数,高位补,1,。这是因为负数在机器内均用补码表示。例如:,int a=-714000,b;,用二进制数表示的运算过程如下:,符号位,a,的二进制原码表示:,1,1110011 00000000,a,的二进制补码表示:,1,0001101 00000000,b=a2 :,1,1100011 01000000(b,的补码,),b,的二进制原码表示:,1,0011100 11000000,b,的八进制娄 :,-016300,76,4.“,按位与”运算(,&,),运算符,&,的功能:把参加运算的两个运算数,按对应的二进制位分别进行“与”运算,当两个相应的位都为,1,时,该位的结果为,1,;否则为,0.,例如,表达式,12&10,的运算如下:,12,:,00001100,&10: 00001010,结果:,00001000,77,5.“,按位异或”运算(,),异或运算的功能:参与运算的两个运算数中相对应的二进制位上,若数相同,则该位的结果为,0,;数不同,则该位的结果为,1,。例如:,00110011,11000011,结果:,11110000,78,6.“,按位或”运算(,|,),按位“或”运算功能:参加运算的两个运算数中,只要两个相应的二进制位中有一个为,1,,该位的运算结果即为,1;,只有当两个相应位的数都为,0,时,该位的运算结果才为,0,。例如:,0123,:,01010011,014,:,00001100,结果:,01011111,79,第十六章文件,知识点,1,:文件指针,文件指针,实际上是指向一个结构体类型的指针变量;这个结构体中包含有诸如:缓冲区的地址、在缓冲区中当前存取的字符的位置、对文件是“读”还是“写”、是否已经遇到文件结束标志等信息。我们不必去了解其中的细节,所有一切都在,stdio.h,头文件中进行了定义;并称此结构体类型名为,FILE,可以用此类型名来定义文件指针。定义文件类型指针变量的一般形式为:,FILE *,指针变量名;,例如:,FILE *fp1,*fp2;,fp1,fp2,均被定义为指向文件类型的指针变量,称为文件指针。,80,知识点,2,:打开文件,1.fopen,函数。用于打开文件。,(,1,)调用形式如下:,FILE *fp;,fp=fopen(,文件名,文件使用方式,),;,例如:,fp=fopen(“C:abc.dat”,”w”);,,打开,C,盘上的文件,abc.dat,,并对此文件可进行“写”操作。文件名和使用方式都用字符串表示。,(,2,)应当熟悉常用文件使用方式 的表示方式和功能,如下表:,81,使用方式,含义(用于文本文件),使用方式,含义(用于二进制文件),“,r”(,只读,),为读而打开文本文件,“,rb”(,只读,),为读打开二进制文件,“,w”(,只写,),为写而打开文本文件,“,wb”(,只写,),为写建立新二进制文件,“,a”(,追加,),向文本文件尾添加数据,“,ab” (,追加,),向二进制文件尾添加数据,“,r+”,或,“,rw”(,读写,),为读,/,写而打开文本文件,“,rb+” (,读写,),为读,/,写打开二进制文件,“,w+,或,“,wr” (,写读,),为写,/,读建立新文本文件,“,wb+” (,写读,),为写,/,读建立新二进制文件,“,a+,或,“,ar” (,写读,),为添加,/,读打开文本文件,“,ab+” (,写读,),为添加,/,读打开二进制文件,82,知识点,4,:关闭文件,当文件的读(写)操作完成这后,必须将它关闭。关闭文件可调用库函数,fclose,来实现,,fclose,函数的调用形式如下:,fclose(,文件指针,),fclose(fp);,,其中,fp,已指向某文件。,fclose,函数作用是使文件指针,fp,与所指文件脱离联系,并由系统妥善处理该文件缓冲区的重要剩余数据。,83,知识点,5,:文件输入和输出函数,当成功地打开文件之后,接下来的事情就是对文件进行输入或输出操作。,1.,调用,putc(,或,fputc),函数输出一个字符,putc,函数的调用形式如下“,putc(ch,fp);,ch,是待输出的某个字符,可以是一个字符常量,也可以是一个字符变量。,fp,是文件指针。功能是将字符,ch,写到文件指针,fp,所指的文件中去。成功则返回所输出的字符;失败返回一个,EOF,值。,EOF,是,stdio.h,库函数文件中定义的符号常量,其值等于,-1.,fputc,函数的调用形式和函数的功能与,putc,函数完全相同。,84,例:把从键盘输入的文本按原样输出到名为,file_a.dat,文件中,用字符,作为键盘输入结束标志。,操作步骤:,1.,打开文件;,2.,从键盘输入一个字符。,3.,判输入的字符是否是字符,若是,结束循环,执行步骤(,7,)。,4.,把刚输入的字符输出到文件中。,5.,从键盘输入一个字符。,6.,重复步骤(,3,)和(,5,)。,7.,关闭文件。,8.,程序结束。,#include “stdio.h”,main(), FILE *fpout;,char ch;,if(fpout=fopen(“fele_a.dat”,”w”)=NULL),printf(“Cant open this file!n”);exit(0);,ch=getchar();,while(ch!=),fputc(ch,fpout);ch=getchar();fclose(fpout);,85,2.,调用,getc(,或,fgetc),函数输入一个字符,getc,函数的调用形式如下:,ch=getc(pf);,此处,pf,是文件指针;函数的功能是从,pf,指定的文件中读入一个字符,并把它作为函数值返回。以上表达式中,getc,函数把文件中讲稿的一个字符赋给变量,ch,。,fgetc,函数的调用形式和函数的功能与,getc,函数完全相同。,例:把一个已存在磁盘上的,file_a.dat,文本文件中的内容,原样输出到终端屏幕上。,86,步骤:,1.,打开文件。,2.,从指定文件中讲稿一个字符。,3.,读入的是否是文件结束标志;若是,结束循环,执行步骤(,7,)。,4.,把刚输入的字符输出到终端屏幕。,5.,从文件中再读入一个字符。,6.,重复步骤(,3,)和(,5,)。,7.,关闭文件。,8.,程序结束。,#include “stdio.h”,main(), FILE *fpin;,char ch;,if(fpin=fopen(“file_a.dat”,”r”)=NULL),printf(“Cant open this file!n”);exit(0);,ch=fgetc(fpin);,while(ch!=EOF) putchar(ch); ch=fgetc(fpin);,fclose(fpin);,87,知识点,6,:文件结束的标志,文本文件可用预定义符,EOF,作为文件结束标志。当把数据以二进制形式存放到文件中时,就会有,-1,值出现,因此不能采用,EOF,作为二进制文件的结束标志。为解决这一问题,提供一个,feof,函数,判断文件是否结束。如果遇到文件结束,函数,feof(fp),的值为,1,,否则为,0.feof,函数既可判断二进制文件又可判断文本文件。,88,知识点,7,:,fscanf,函数和,fprintf,函数,按格式进行输入和输出的函数只能用文本文件。,1.fscanf,函数。函数的调用形式为:,fscanf(,文件指针,格式控制字符串,输入项表,),例如:,fscanf(fp,”%d%d”,,将从,fp,所指的文件中读入两个整数放入变量,a,和,b,中。,注意:文件中的两个整数之间用间隔符隔开。,2.fprintf,函数。函数的调用形式:,fprintf(,文件指针,格式控制字符串,输出项表,),例如:,fprintf(fp,”%d%d”,a,b);,,是把两个整型变量中的整数按,%d,格式输出到,fp,所指的文件中。,89,知识点,8,:,fgets,函数和,fputs,函数,1.fgets,函数,fgets,函数用来从文件中读入字符串。,fgets,函数的调用形式如下:,fgets(str,n,fp)
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 管理文书 > 施工组织


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!