1、第十三章 结构体与共用体,第十三章 结构体与共用体,13.1 结构体类型变量的定义和引用,结构体类型的定义形式: struct 结构体名 成员项表列 ;,第十三章 结构体与共用体,有三种形式定义结构体类型的变量 (1)先定义结构体类型,再定义结构体类型变量: struct stu / *定义学生结构体类型* / char name20; / * 学生姓名* /char sex; / * 性别* /long num; / *学号* /float score3; / * 三科考试成绩* / ; struct stu student1,student2;/ * 定义结构体类型变量* / struct
2、 stu student3,student4; 用此结构体类型,可以定义更多的该结构体类型变量。,13.1 结构体类型变量的定义和引用 一、结构体类型变量的定义,第十三章 结构体与共用体,(2)定义结构体类型同时定义结构体类型变量: struct data int day;int month;int year; time1,time2; 也可以再定义如下变量: struct data time3,time4; 用此结构体类型,同样可以定义更多的该结构体类型变量。,13.1 结构体类型变量的定义和引用 一、结构体类型变量的定义,第十三章 结构体与共用体,(3)直接定义结构体类型变量: struc
3、t char name20; / *学生姓名* /char sex; / *性别* /long num; / *学号* /float score3; / *三科考试成绩* / person1,person2; / *定义该结构体类型变量* / 该定义方法由于无法记录该结构体类型,所以除直接定义外,不能再定义该结构体类型变量。,13.1 结构体类型变量的定义和引用 一、结构体类型变量的定义,第十三章 结构体与共用体,引用的形式为: . 若定义的结构体类型及变量如下: struct data int day;int month;int year; time1,time2; 则变量time1和tim
4、e2各成员的引用形式为: time1.day、time1.month、time1.year及time2.day、 time2.month、time2.year。 其结构体类型变量的各成员与相应的简单类型变量使用方法完全相同。,13.1 结构体类型变量的定义和引用 二、结构体类型变量的引用,第十三章 结构体与共用体,结构体类型变量的定义和初始化为: struct stu / *定义学生结构体类型* / char name20; / * 学生姓名* /char sex; / * 性别* /long num; / *学号* /float score3; / * 三科考试成绩* / ; struct
5、stu student=“liping“,f,970541,98.5,97.4,95; 上述对结构体类型变量的三种定义形式均可在定义时初始化。,13.1 结构体类型变量的定义和引用 二、结构体类型变量的初始化和赋值,第十三章 结构体与共用体,结构体类型变量完成初始化后,即各成员的值分别为: student.name=“liping“、student.sex=f、student.num=970541、student.score0=98.5、student.score1=97.4、student.score2=95。 其存储在内存的情况如图:,13.1 结构体类型变量的定义和引用 二、结构体类型变
6、量的初始化和赋值,在ANSI C中允许相同类型的结构变量相互赋值。,第十三章 结构体与共用体,例13.1外部结构变量初始化。 struct stu /*定义结构*/ int num;char *name;char sex;float score; boy2,boy1=102,“Zhang ping“,M,78.5; main( ) boy2=boy1; printf(“Number=%dnName=%sn”,boy2.num,boy2.name);printf(“Sex=%cnScore=%fn”,boy2.sex,boy2.score); ,13.1 结构体类型变量的定义和引用 二、结构体类
7、型变量的初始化和赋值,第十三章 结构体与共用体,例13.2给结构变量赋值并输出其值。 main( ) struct stu int num;char *name;char sex;float score; boy1,boy2;boy1.num=102; boy1.name=“Zhang ping“;printf(“input sex and scoren“);scanf(“%c %f“,printf(“Sex=%cnScore=%fn“,boy2.sex,boy2.score); ,13.1 结构体类型变量的定义和引用 二、结构体类型变量的初始化和赋值,第十三章 结构体与共用体,C允许定义嵌套
8、的结构体类型 struct data struct stu int day; char name20;int mouth; struct data birthday; int year; long num; ; person; 如果成员本身又是一个结构则必须逐级找到最低级的成员才能使用:用若干“.”运算符,逐级引用到最低级。 如:person.name 、person.birthday.day、person.birthday.month、person.birthday.year、 person.num 。,13.1 结构体类型变量的定义和引用 二、结构体类型变量的初始化和赋值,第十三章 结构体
9、与共用体,结构体类型数组的定义形式为: struct stu char name20; char sex; long num; float score3; ; struct stu stud20; / *该数组有2 0个结构体类型元素* / 其数组元素各成员的引用形式为: stud0.name 、stud0.sex 、stud0.scorei; stud1.name 、stud1.sex 、stud1.scorei; stud19.name 、stud19.sex 、stud19.scorei;,13.2 结构体数组的定义和引用,第十三章 结构体与共用体,例13.3计算学生的平均成绩和不及格的
10、人数。 struct stu int num;char *name;char sex;float score; boy5=101,“Li ping”,M,45,102,“Zhang ping”,M,62.5,103,“He fang”,F,92.5,104,“Cheng ling”,F,87, 105,“Wang ming“,M,58,; main( ) int i,c=0; float ave,s=0;for(i=0;i5;i) s=boyi.score;if(boyi.score60) c=1;printf(“s=%fn”,s); ave=s/5;printf(“average=%fnco
11、unt=%dn“,ave,c); ,13.2 结构体数组的定义和引用,第十三章 结构体与共用体,已知结构体stu,定义指向结构体类型变量的指针变量: struct stu char name20;long number;float score4; stu1; struct stu *p1, *p2 ;,13.3 结构体指针的定义和引用 一、指向结构体类型变量的使用,第十三章 结构体与共用体,引用形式: 指针变量名成员名; 当指针真正指向了结构体型变量后,以下三种引用形式是等价的: 1、结构体变量.成员名; 2、(*指针变量名).成员名 3、指针变量名-成员名;,13.3 结构体指针的定义和引用
12、 一、指向结构体类型变量的使用,第十三章 结构体与共用体,例13.4输入学生的基本情况,然后输出。 struct data int day,month,year; ; struct stu char name20; long num;struct data birthday; st; main( ) struct stu *student; student= ,13.3 结构体指针的定义和引用 一、指向结构体类型变量的使用,第十三章 结构体与共用体,结构指针变量可以指向一个结构数组,这时结构指针变量的值是整个结构数组的首地址。结构指针变量也可指向结构数组的一个元素,这时结构指针变量的值是该结构
13、数组元素的首地址。设ps为指向结构数组的指针变量,则ps也指向该结构数组的0号元素,ps1指向1号元素,psi则指向i号元素。,13.3 结构体指针的定义和引用 二、指向结构体类型数组的指针的使用,第十三章 结构体与共用体,例13.5用指针变量输出结构数组。 struct stu int num; char *name; char sex; float score; boy5=101,“Zhou ping”,M,45, 102,“Zhang ping”,M,62.5,103,“Liou fang”,F,92.5, 104,“Cheng ling”,F,87,105,“Wang ming”,M,
14、58; main( ) struct stu *ps;printf(“NotNametttSextScoretn“);for(ps=boy;psnum,ps-name,ps-sex,ps-score); ,13.3 结构体指针的定义和引用 二、指向结构体类型数组的指针的使用,第十三章 结构体与共用体,用指针变量作函数参数进行传送,由实参传向形参的只是地址,从而减少了时间和空间的开销。,13.3 结构体指针的定义和引用 三、用指向结构体的指针作为函数的参数,第十三章 结构体与共用体,例13.6计算一组学生的平均成绩和不及格人数。用结构指针变量作函数参数编程。 struct stu int num
15、;char *name;char sex;float score;boy5=101,“Li ping“,M,45,102,“Zhang ping“,M,62.5,103,“He fang“,F,92.5,104,“Cheng ling“,F,87,105,“Wang ming“,M,58,;,13.3 结构体指针的定义和引用 三、用指向结构体的指针作为函数的参数,第十三章 结构体与共用体,main( ) struct stu *ps;void ave(struct stu *ps);ps=boy;ave(ps); void ave(struct stu *ps) int c=0,i;float
16、 ave,s=0;for(i=0;iscore;if(psscore60) c=1;printf(“s=%fn“,s);ave=s/5;printf(“average=%fncount=%dn“,ave,c); ,13.3 结构体指针的定义和引用 三、用指向结构体的指针作为函数的参数,第十三章 结构体与共用体,常用的内存管理函数: 1.分配内存空间函数malloc。 调用形式: (类型说明符*) malloc (size) 功能:在内存的动态存储区中分配一块长度为“size“ 字节的连续区域。函数的返回值为该区域的首地址。 “类型说明符”表示把该区域用于何种数据类型。 (类型说明符*)表示把返
17、回值强制转换为该类型指针。 “size”是一个无符号数。 如: pc=(char *) malloc (100); 表示分配100个字节的内存空间,并强制转换为字符数组类型,函数的返回值为指向该字符数组的指针,把该指针赋予指针变量pc。,13.4 链表的建立、插入和删除 一、单链表,第十三章 结构体与共用体,2.分配内存空间函数 calloc 调用形式: (类型说明符*)calloc(n,size) calloc 也用于分配内存空间 功能:在内存动态存储区中分配n块长度为“size”字节的连续区域。函数的返回值为该区域的首地址。 (类型说明符*)用于强制类型转换。 calloc函数与mallo
18、c 函数的区别:在于一次可以分配n块区域。 如:ps=(struet stu*) calloc(2,sizeof (struct stu); 其中的sizeof(struct stu)是求stu的结构长度。因此该语句的意思是:按stu的长度分配2块连续区域,强制转换为stu类型,并把其首地址赋予指针变量ps。,13.4 链表的建立、插入和删除 一、单链表,第十三章 结构体与共用体,3.释放内存空间函数free 调用形式: free(void*ptr); 功能:释放ptr所指向的一块内存空间,ptr 是一个任意类型的指针变量,它指向被释放区域的首地址。被释放区应是由malloc或calloc函数
19、所分配的区域。,13.4 链表的建立、插入和删除 一、单链表,第十三章 结构体与共用体,4.用typedef定义类型 可以用typedef定义的新的类型名来代替已有的类型名。 如:typedef int INTEGER;typedef float REAL; 在上面的定义中,指定用INTEGER代表int类型,REAL代表float。 以下两行等价: int i,j;float a,b; INTEGER i,j; REAL a,b;,13.4 链表的建立、插入和删除 一、单链表,第十三章 结构体与共用体,定义一个新的类型名的方法是: (1)先按定义变量的方法写出定义体(如:int i;) (2
20、)将变量名换成新类型名(如:将i换成COUNT)。 (3)在最前面加typedef (如:typedef int COUNT)。 (4)然后可以用新类型名去定义变量。 定义一个新的类型名的好处是:书写方便、适应习惯。 说明:typedef 只对原有类型起新的名字,并没有构造新的类型。,13.4 链表的建立、插入和删除 一、单链表,第十三章 结构体与共用体,例13.7分配一块区域,输入一个学生数据。 main( ) struct stu int num; char *name; char sex; float score; *ps;ps=(struct stu*)malloc(sizeof(st
21、ruct stu);psnum=102; psname=“Zhang ping“;pssex=M; psscore=62.5;printf(“Number=%dnName=%sn“,psnum,psname);printf(“Sex=%cnScore=%fn“,ps-sex,ps-score);free(ps); ,13.4 链表的建立、插入和删除 一、单链表,第十三章 结构体与共用体,单链表有一个头结点head,指向链表在内存的首地址。链表中的每一个结点的数据类型为结构体类型,结点有两个成员:整型成员和指向下一个结构体类型结点的指针即下一个结点的地址。 链表按此结构对各结点的访问需从链表的头
22、找起,后续结点的地址由当前结点给出。无论在表中访问那一个结点,都需要从链表的头开始,顺序向后查找。链表的尾结点由于无后续结点,其指针域为空,写作为NULL。,13.4 链表的建立、插入和删除 一、单链表,第十三章 结构体与共用体,链表中的各结点在内存的存储地址不是连续的,其各结点的地址是在需要时向系统申请分配的,系统根据内存的当前情况,既可以连续分配地址,也可以跳跃式分配地址。,13.4 链表的建立、插入和删除 一、单链表,第十三章 结构体与共用体,链表结点的数据结构定义: struct node int num;struct node *p; ; 在链表结点的定义中,除一个整型的成员外,成员
23、p是指向与结点类型完全相同的指针。,13.4 链表的建立、插入和删除 一、单链表,第十三章 结构体与共用体,1.建立链表 是指从无到有地建立起一个链表,即一个一个地输入各结点数据,并建立起前后相链的关系。 单链表的创建过程有以下几步: 1 ) 定义链表的数据结构。 2 ) 创建一个空表。 3 ) 利用malloc( )函数向系统申请分配一个结点。 4 ) 将新结点的指针成员赋值为空。若是空表,将新结点连接到表头;若是非空表,将新结点接到表尾。 5 ) 判断一下是否有后续结点要接入链表,若有转到3 ),否则结束。,13.4 链表的建立、插入和删除 二、链表的建立、输出、插入和删除,第十三章 结构
24、体与共用体,例13.8写一函数建立一个有若干学生数据的单向链表。 算法: (1)头指针head开辟一个空间,并使指针p和q指向head所开辟的空间; (2)输入学号和成绩; (3)如果学号不等于0,p去开辟新的空间,否则程序流程转到步骤(7); (4)将数据存入新结点的成员变量中; (5)根据指针q和p连接新旧两个结点后,使q指向p所开辟的空间; (6)输入学号和成绩,并转到步骤(3) (7)给p的next成员赋NULL。,13.4 链表的建立、插入和删除 二、链表的建立、输出、插入和删除,第十三章 结构体与共用体,# indclude typedef struct student long
25、num; float score; struct student * next; LIST; LIST * creat ( ) long n; float s; LIST * head,*p, *q;head=(LIST ) malloc(sizeof ( LIST ) ); while ( n!=0) p=(LIST *)malloc(sizeof (LIST); p-num =; p-score =s; q- next = p; q=p ; scanf (“%ld ,%f“,&n,&s); q- next = NULL; return ( head ); void print ( LIST
26、 * head ) * 函数体是空的,在例13.7给出其函数*/ main ( ) LIST * head; head= creat ( ) ; print ( head ); ,13.4 链表的建立、插入和删除 二、链表的建立、输出、插入和删除,第十三章 结构体与共用体,2. 输出链表 单链表的输出过程有以下几步 (1) 找到表头。 (2) 若是非空表,输出结点的值成员,是空表则退出。 (3) 跟踪链表的增长,即找到下一个结点的地址。 (4) 转到(2 )。,13.4 链表的建立、插入和删除 二、链表的建立、输出、插入和删除,第十三章 结构体与共用体,例13.9将链表中各结点的数据依此输出。
27、 其算法是:根据头指针head,使p指向第一个结点,输出p所指的结点,然后使p后移一个结点,再输出,直到链表的尾结点。void print ( LIST * head ) / *head 指向头结点*/ LIST * p ;p= head -next; / *p指向第一个结点*/while ( p! =NULL) printf (“%ld %5.1fn“,p-num ,p-score);p=p-next; / *指向下一个结点*/,13.4 链表的建立、插入和删除 二、链表的建立、输出、插入和删除,第十三章 结构体与共用体,3. 对链表的插入 例13.10 设链表中各结点中的成员项num(学号
28、)是按学号由小到大顺序排列的。将一个结点插入到链表中,使插入后的链表仍保持原来的规律。 步骤如下: (1)查找插入位置 (2)插入新结点,即新结点与插入点到前后的结点连。,13.4 链表的建立、插入和删除 二、链表的建立、输出、插入和删除,第十三章 结构体与共用体,# includestdio.h typedef struct student LIST; LIST * creat ( ) void print (LIST * head ) insert (LIST *head ,LIST *stud ) LIST * p, *q;q=head; p=headnext;while ( p! =N
29、ULL qnext =stud ; main ( ) LIST * head ,stu ; head=creat ( ); print (head );scanf (“%1d,%f“,&stu.num,&stu .score);insert (head ,&stu); print (head ); ,13.4 链表的建立、插入和删除 二、链表的建立、输出、插入和删除,第十三章 结构体与共用体,4.对链表的删除 例13.11写一函数以删除指定的结点。假设学号作为删除结点的标志。 这相当于幼儿园一队小孩中有一人想离队解手,经老帅同意后他的从手与前后两个小孩脱钩,离开队列,而原来在他前面小孩的手去拉
30、原来在他后面小孩的手,这就是删除“结点的“的操作。 步骤如下: (1)查找删除结点的位置; (2)删除结点,即将该结点的前一个结点与后一个结点连接。,13.4 链表的建立、插入和删除 二、链表的建立、输出、插入和删除,第十三章 结构体与共用体,# includestdio.htypedef struct student . LIST;LIST * creat ( ) void print (LIST *head ) int del ( LIST * head,long num ) LIST *p, *q;if(head next = = NULL) printf (“List is null!
31、 n”); return 0; q= head; p= head neat ; while ( p! = NULL & num! =pnum ) q = p; p=pnext ; if(p = = NULL) printf (“ Not heen found. /n“ ); reurn 0 ;else qnext=next ; free ( p ); return 1; ,13.4 链表的建立、插入和删除 二、链表的建立、输出、插入和删除,第十三章 结构体与共用体,main ( ) int a ;long num;LIST *head;head= creat ( );print (head )
32、;scanf (“ %1d“,&num );a= del (head ,num );if (a! =0 ) print (head ); /*如果删除成功,输出链表*/ ,13.4 链表的建立、插入和删除 二、链表的建立、输出、插入和删除,第十三章 结构体与共用体,“共用体”类型变量的定义形式为:union 共用体名 成员表列 变量表列; 如:union data int i ;char ch;float f; a,b,c ;,13.5 共用体 一、共用体的概念,第十三章 结构体与共用体,也可以将类型定义与变量定义分开:union data int i;char ch;floar f; ;un
33、ion data a,b,c; 也可以直接定义共用体变量:union int i;char ch;float f; a,b,c;,13.5 共用体 一、共用体的概念,第十三章 结构体与共用体,只有先定义用体变量才能引用它,而且不能直接引用共用体变量,而只能引用共用体变量中的成员。如:前面定义了a,b,c为共用体变量,下面的引用方式是正确的: a.i (引用共用体变量的整型变量i) a.ch(引用共用体变量中的字符变量ch) a.f (引用共用体变量中的实型变量f),13.5 共用体 二、共用体变量的引用方式,第十三章 结构体与共用体,在使用共用体类型数据时要注意以下特点: (1)同一个内存段可
34、以用来放几个不同类型的成员,但在每一瞬时只能存放其中一种,而不是同时存放几种。即,每一瞬时只有一个成员起作用,其它的成员不起作用,即不是同时都存在和起作用。 (2)共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员就失去作用。如有以下赋值语句:a.i = l; a.c = a ; a.f = l.5在完成以上三个赋值运算以后,只有a.f是有效的,a.i 和a.c 已经不是原来的值。,13.5 共用体 三、共用体类型数据的特点,第十三章 结构体与共用体,(3) 共用体变量的地址和它的各成员的地址都是同一地址。如:a,&a.i,&a.c,&a.f都是同一地址值。 (4)
35、不能对共用体变量名赋值,也不能企图引用变量名来得到成员的值,又不能在定义共用体变量时对它初始化。如:下面这都是不对的:union int i;char ch;float f; a= 1 , a , 1.5 ; (不能初始化)a=1; (不能对共用体变量赋值)m=a; (不能引用共用体变量名以得到值),13.5 共用体 三、共用体类型数据的特点,第十三章 结构体与共用体,(5)不能把共用体变量作为函数参数,也不能使函数带回共用变量,但可以使用指向共用体变量的指针(与结构体变量这种用法相仿)。 (6)共用体类型可以出现在结构体类型定义中,也可以定义共用体数组。反之,结构体也可以出现在共用体类型定义中,数组也可以作为共用体的成员。,13.5 共用体 三、共用体类型数据的特点,