1、结构体共用休和用户定义类型(优选)结构体共用休和用户定义类型结构体类型和结构体变量的定义l应先定义结构体类型,再定义结构体变量如:struct student int num;char name20;char sex;int age;float score;char addr30;struct student stu1,stu2;又如:#define STUDENT struct studentSTUDENT int num;char name20;char sex;int age;float score;char addr30;STUDENT stu1,stu2;stu1100102 Wan
2、gLi F 20 98 Beijing100101 LiXin M 19 90.5 Shanghaistu2结构体类型和结构体变量的定义l也可以直接定义结构体变量。l一般形式lstructll 类型标识符 成员名;l 类型标识符 成员名;l l变量名表列;如:struct int num;char name20;char sex;int age;float score;char addr30;stu1,stu2;本例中,结构体类型没有被命名,这称为无名结构体。无名结构体可以用来直接定义变量,但本类型只能使用一次,后面无法再用。结构指针变量的定义l结构指针变量说明的一般形式为lstruct 结构
3、名*结构指针变量名l例如,在前面的例题中定义了stu这个结构,如要说明一个指向stu的指针变量pstu,可写为 struct stu*pstu;l当然也可在定义stu结构时同时说明pstu。l结构指针变量也必须要先赋值后才能使用。赋值是把结构变量的首地址赋予该指针变量。l要特别注意的是,不能把结构类型名赋予一个指针变量。如果boy是被说明为stu类型的结构变量,则lpstu=&boy 是正确的;lpstu=&stu 是错误的。结构体类型和结构体变量的定义l说明l结构体的成员名可以与程序中的变量名相同,二者不代表同一对象。l需要特别说明的是,结构体类型与结构体变量不是一个概念p结构体类型结构体类
4、型是用户自定义的结构型数据类型,它在定义时并不需要分配内存。你不能给一种结构体类型赋值,当然也不能对它存取和运算。1.结构体变量结构体变量就是具有特定结构体类型的变量,编译时系统将为其分配相应的存储空间。可以对其赋值、存取以及运算。结构体类型和结构体变量的定义例:struct student int num;char name20;char sex;int age;float score;char addr30;注意:这是结构体定义,只描述结构的组织形式,student是结构体类型名,编译时并不为它分配内存namenumsexagescoreaddr4字节4字节20字节1字节4字节30字节结构
5、体只有在实例化时才为每个结构体成员分配内存。结构体类型和结构体变量的定义l结构体中的成员(即“域”),可以是普通变量也可以是一个结构体变量。也就是说结构体可以嵌套使用。如:struct date int month;int day;int year;struct student int num;char name20;struct date birthday;stu;numnamebirthdaymonthdayyear或:struct student int num;char name20;struct date int month;int day;int year;birthday;stu
6、;结构体变量的初始化l形式一lstruct 结构体名ll 类型标识符 成员名;l 类型标识符 成员名;l .l;lstruct 结构体名 结构体变量=初始数据;例:struct student int num;char name20;char sex;int age;char addr30;struct student stu1=112,“Wang Lin”,M,19,“200 Beijing Road”;结构体变量的初始化l形式二lstruct 结构体名ll 类型标识符 成员名;l 类型标识符 成员名;l .l结构体变量=初始数据;例 struct student int num;char
7、name20;char sex;int age;char addr30;stu1=112,“Wang Lin”,M,19,“200 Beijing Road”;.REAL f1,f2;功能在内存动态存储区中分配n块长度为“size”字节的连续区域。while(p-link!=x)链表使用完毕后建议销毁它,因为链表本身会占用内存空间。赋值是把结构变量的首地址赋予该指针变量。(*结构指针变量).calloc函数与malloc 函数的区别仅在于一次可以分配n块区域。例:union data作者张旭仟 版权所有 欢迎盗版int age;(2)向函数传递结构体变量 int num;其中成员(分量)运算符
8、“.list(head);struct student结构体变量的初始化l形式三lstructll 类型标识符 成员名;l 类型标识符 成员名;l .l结构体变量=初始数据;例:struct int num;char name20;char sex;int age;char addr30;stu1=112,“Wang Lin”,M,19,“200 Beijing Road”;结构体变量的引用l在定义了结构体变量以后,当然可以引用这个变量。l引用规则:l结构体中的成员只能单独使用,它的作用与地位相当于普通变量。l引用方式有三种l结构体变量名.成员l指针变量名成员l(*指针变量名).成员l其中成员
9、(分量)运算符“.”,结构指向运算符“”,与前面已经接触过的下标运算符、圆括号运算符()的优先级均为 1,结合性从左向右结构体变量的引用l使用成员(分量)运算符“.”引用结构体成员如:struct student int num;char name20;char sex;int age;float score;char addr30;stu1,stu2;stu1.score=85.5;stu1.num=10;stu1.score+=stu2.score;stu1.age+;结构体变量的引用l使用结构指针变量,往往能更方便地访问结构变量的各个成员,其访问的一般形式为l(*结构指针变量).成员名l
10、或为l结构指针变量成员名l例如(*pstu).num 或者pstunuml应该注意,(*pstu)两侧的括号不可少,因为成员符“.”的优先级高于“*”。如去掉括号写作*pstu.num则等效于*(pstu.num),这样,意义就完全不对了。结构体变量的引用l示例结构指针变量的具体说明和使用方法 struct stu int num;char*name;char sex;float score;boy1=102,Zhang ping,M,78.5,*pstu;main()pstu=&boy1;printf(Number=%dnName=%sn,boy1.num,boy1.name);printf
11、(Sex=%cnScore=%fnn,boy1.sex,boy1.score);printf(Number=%dnName=%sn,(*pstu).num,(*pstu).name);printf(Sex=%cnScore=%fnn,(*pstu).sex,(*pstu).score);printf(Number=%dnName=%sn,pstu-num,pstu-name);printf(Sex=%cnScore=%fnn,pstu-sex,pstu-score);结构体变量的引用例中,printf语句试图整体引用结构体变量stu1的用法是不可行的。举例:struct student int
12、 num;char name20;char sex;int age;float score;char addr30;stu1,stu2;printf(“%d,%s,%c,%d,%f,%sn”,stu1);l说明:(1)不能将一个结构体变量作为一个整体进行输入和输出。5 Shanghai int num;例 struct student例中,printf语句试图整体引用结构体变量stu1的用法是不可行的。例:struct student stud*head;(类型说明符*)用于强制类型转换。stu1=112,“Wang Lin”,M,19,“200 Beijing Road”;union dat
13、a int num;作者张旭仟 版权所有 欢迎盗版char name20;short i;float f;你不能给一种结构体类型赋值,当然也不能对它存取和运算。共用体变量任何时刻只有一个成员存在。printf(%d,a.pstu=&stu 是错误的。char ch;结构体变量的引用l说明l(2)但是,将一个结构体变量赋值给另一个结构体变量是允许的如:struct student int num;char name20;char sex;int age;float score;char addr30;stu1,stu2;stu1=stu2;结构体变量的引用l说明l(3)对于嵌套的结构体,内部成员
14、可以逐级引用例:struct student int num;char name20;struct date int month;int day;int year;birthday;stu1,stu2;结构体变量的引用l说明l(4)不能对结构体变量做关系运算例:struct student int num;char name20;char sex;int age;float score;char addr30;stu1,stu2;if(stu1=stu2)例中,语句if(stu1=stu2)是错误的函数之间结构体变量的数据传递l函数之间结构体变量的数据传递分以下几种情况l(1)向函数传递结构体
15、变量的成员l(2)向函数传递结构体变量l(3)向函数传递结构体的指针l例如通过函数给结构体成员赋值#include stdio.hstruct AB char a10;int b;getdata(struct AB*p)scanf(%s%d,&p-a,&p-b);main()struct AB s;getdata(&s);printf(%s,%dn,s.a,s.b);动态存储分配l动态存储分配的概念l变量、数组一旦定义,其存储长度在整个程序中是固定不变的,因此被称为“静态存储分配”。然而,实际编程中,有时候所需的内存空间取决于实际输入的数据,无法预先确定。l为了解决上述问题,语言提供了一些内存
16、管理函数,可以按需要动态地分配内存空间,也可把不再使用的空间回收(释放),这种机制称为“动态存储分配”。l常用的动态存储分配函数有以下三个 l分配内存空间函数 mallocl分配内存空间函数 callocl释放内存空间函数 freel使用以上函数必须有文件包含命令#include stdlib.h 动态存储分配l分配内存空间函数mallocl调用形式l(类型说明符*)malloc(size)l功能在内存的动态存储区中分配一块长度为size字节的连续区域。函数的返回值为该区域的首地址。l其中“类型说明符”表示把该区域用于何种数据类型。l(类型说明符*)表示把返回值强制转换为该类型指针。l“siz
17、e”是一个无符号数。l例如char*pc;pc=(char*)malloc(100);l表示动态分配100个字节的内存空间,并强制转换为字符数组类型,函数的返回值为指向该字符数组的指针,把该指针赋予指针变量pc。动态存储分配l分配内存空间函数 callocl calloc 也用于分配内存空间。l调用形式l (类型说明符*)calloc(n,size)l功能在内存动态存储区中分配n块长度为“size”字节的连续区域。函数的返回值为该区域的首地址。l(类型说明符*)用于强制类型转换。lcalloc函数与malloc 函数的区别仅在于一次可以分配n块区域。l例如struct stu*ps=(stru
18、et stu*)calloc(2,sizeof(struct stu);l其中的sizeof(struct stu)是求stu的结构长度。因此该语句的意思是按stu的长度分配2块连续区域,强制转换为stu类型,并把其首地址赋予指针变量ps。动态存储分配l释放内存空间函数freel调用形式lfree(void*ptr);l功能释放ptr所指向的一块内存空间,ptr是一个任意类型的指针变量,它指向被释放区域的首地址。被释放区应是由malloc或calloc函数所分配的区域。l例如free(pc);free(ps);作者张旭仟 版权所有 欢迎盗版作者张旭仟 版权所有 欢迎盗版char name20;
19、作者张旭仟 版权所有 欢迎盗版float f1,f2;如果采用动态分配的办法存储学生记录,一次为一条记录分配一块空间(我们称之为结点),这样就无须预先确定学生的准确人数。使用成员(分量)运算符“.不能在定义共用体变量的同时对其初始化。作者张旭仟 版权所有 欢迎盗版类型标识符 成员名;char sex;pstu=&boy1;short i;作者张旭仟 版权所有 欢迎盗版你不能给一种结构体类型赋值,当然也不能对它存取和运算。int i;char ch;float score;typedef struct node作者张旭仟 版权所有 欢迎盗版char addr30;动态链表的概念 l如果采用动态分
20、配的办法存储学生记录,一次为一条记录分配一块空间(我们称之为结点),这样就无须预先确定学生的准确人数。如果某学生退学,也可删去该结点,并释放该结点占用的存储空间。l每个结点之间物理上可以是不连续的。结点之间的联系用指针实现,即在结点结构中定义一个成员项存放下一结点的首地址,这个成员,称为指针域。l在第一个结点的指针域内存入第二个结点的首地址,在第二个结点的指针域内又存放第三个结点的首地址,如此串连下去直到最后一个结点。最后一个结点因无后续结点连接,其指针域置为空(NULL)。这样一种连接方式,在数据结构中称为“链表”。动态链表的概念l链表的组成l链表中的所有结点都是同一种结构类型。包括一个头指
21、针,是一个结构类型的指针变量,用来存放链表第一个结点的首地址;若干个结点,用来存放用户需要的实际数据以及链接节点的指针。l下图为一简单链表的示意图 头结点head没有数据域,只负责存放第一个结点的首地址。除head外,每个结点都分为两个域,其中数据域存放各种实际的数据,如学号、姓名等;指针域存放下一结点的首地址。动态链表的概念l链表的结点l链表的结点都是结构体类型,如struct student int num;float score;struct student*next;l其中l成员num和score用来存放结点中用户需要用到的数据;lnext是指针类型的成员,它指向struct stud
22、ent类型数据(也就是next所在的结构体类型)链表操作的建立与操作实例l定义链表的结点结构typedef struct nodechar name20;struct node*link;stud;这样就定义了一个单链表的结构,其中char name20是一个用来存储姓名的字符型数组,指针*link是一个用来存储其直接后继的指针。定义好了链表的结构之后,就可以在数据域中存储适当的数据,如有后继结点,则把链域指向其直接后继,若没有,则置为NULL。链表的建立与操作实例l创建链表stud*creat(int n)stud*p,*h,*s;int i;if(h=(stud*)malloc(sizeo
23、f(stud)=NULL)printf(不能分配内存空间!);return NULL;h-name0=0;/*把表头结点的数据域置空*/h-link=NULL;/*把表头结点的链域置空*/p=h;/*p指向表头结点*/for(i=0;ilink=s;printf(请输入第%d个人的姓名,i+1);scanf(%s,s-name);s-link=NULL;p=s;return(h);注意:由于用到malloc函数,所以在程序的开始部分应有如下包含命令:#include 链表的建立与操作实例l创建遍历链表的函数main()stud*head;head=creat(3);list(head);voi
24、d list(stud*head)stud*p,*q;p=head;while(p-link!=NULL)q=p-link;printf(%sn,q-name);p=q;l调用创建和输出链表的主函数链表的建立与操作实例l根据数据项的值检索链表中的结点l思路对单链表的结点依次扫描,检测其数据域是否是我们所要查好的值,若是返回该结点的指针,否则返回NULL。stud*search(stud*head,char*x)stud*p;char*y;p=head-link;while(p!=NULL)y=p-name;if(strcmp(y,x)=0)return(p);else p=p-link;if(
25、p=NULL)printf(没有查找到该数据!);return NULL;链表的建立与操作实例l测试结点检索函数的主函数main()char fullname20;stud*head,*searchpoint;head=creat(3);printf(请输入你要查找的人的姓名:);scanf(%s,fullname);searchpoint=search(head,fullname);printf(你要查找的人的姓名:%sn,searchpoint-name);链表的建立与操作实例l在单向链表中插入新结点l在单向链表中插入新结点的步骤如下l(1)先创建一个新结点,并用指针p指向该结点。l(2)
26、将q指向的结点的next域的值(即q的后继结点的指针)赋值给p指向结点的next域。l(3)将p的值赋值给q的next域。l通过以上3步就可以实现在链表中由指针q指向的结点后面插入p所指向的结点。可以通过图15形象地展示出这一过程。链表的建立与操作实例l在单向链表中插入新结点 void insert(stud*p)char stuname20;stud*s;if(s=(stud*)malloc(sizeof(stud)=NULL)printf(不能分配内存空间!);exit(0);printf(输入要插入学生结点的姓名:);scanf(%s,stuname);strcpy(s-name,stu
27、name);s-link=p-link;p-link=s;链表的建立与操作实例l测试插入结点函数的主函数main()char fullname20;stud*head,*searchpoint;head=creat(2);printf(输入要在他之后添加结点的那个人的姓名:);scanf(%s,fullname);searchpoint=search(head,fullname);insert(searchpoint);list(head);链表的建立与操作实例l删除单向链表中的结点l在链表内删除节点又三种不同的情形1删除第一个节点只需要将head指向第二个节点2删除最后一个节点,只需要将指向
28、最后一个节点的指针(引用)指向NULL3删除中间节点,只要将需要删除节点的指针指向需要删除节点的下一个节点。stud*del(stud*head,stud*x)stud*p;if(head=x)return head-link;else p=head;while(p-link!=x)p=p-link;if(x-link=NULL)p-link=NULL;else p-link=x-link;return head;链表的建立与操作实例l测试删除结点函数的主函数main()char fullname20;stud*head,*searchpoint;head=creat(3);printf(请输
29、入要删除的学生的姓名:);scanf(%s,fullname);searchpoint=search(head,fullname);del(head,searchpoint);链表的建立与操作实例l销毁一个链表l链表使用完毕后建议销毁它,因为链表本身会占用内存空间。如果一个系统中使用了很多链表,而使用完毕后又不及时销毁它,那么这些垃圾空间积累过多,最终可能导致内存泄漏甚至程序崩溃。void destroy(stud*head)stud*p,*q;p=head;while(p!=NULL)q=p-link;free(p);p=q;head=NULL;共用体的定义l共用体也叫联合体,也是一种构造数
30、据类型。共用体可以使几个不同类型的变量共占同一段内存。l定义形式lunion 共用体名ll 类型标识符 成员名;l 类型标识符 成员名;l .l;l其中union 是关键字,共用体名是用户自定义标示符。例:union data int i;char ch;float f;注意:这里的类型定义在编译时也是不分配内存的。共用体变量的定义l形式一:union data int i;char ch;float f;union data a,b;l形式二:union data int i;char ch;float f;a,b;fchifchiab共用体变量任何时刻只有一个成员存在。共用体变量在编译时被
31、分配内存,长度=最长成员所占字节数。l形式三:union int i;char ch;float f;a,b;共用体变量的引用l引用方式l共用体变量名.成员名l共用体指针名成员名l(*共用体指针名).成员名例:如有以下定义union data int i;char ch;float f;union data a,b,c,*p,d3;a.i、a.ch、a.fp-i、p-ch、p-f(*p).i、(*p).ch、(*p).fd0.i、d0.ch、d0.fl则可以如下方式加以引用:共用体变量的引用l引用规则l不能直接引用共用体变量,只能引用其成员。例:union int i;char ch;floa
32、t f;a;a=1;/*以上语句是错误的*/例:union int i;char ch;float f;a=1,a,1.5;/*以上赋值语句是错误的*/l不能在定义共用体变量的同时对其初始化。共用体变量的引用l共用体变量中起作用的成员是最后一次存放的成员例:union data int i;char ch;float f;union data a;a.ch=a;a.f=1.5;printf(%d,a.i);运行结果:1.5 l可以用一个共用体变量为另一个变量赋值例:float x;union int i;char ch;float f;a,b;a.i=1;a.ch=a;a.f=1.5;b=a;
33、()x=a.f;()共用体举例l将一个整数按字节输出main()union int_char short i;char ch2;x;x.i=24897;printf(i=%on,x.i);printf(ch0=%o,ch1=%on ch0=%c,ch1=%cn,x.ch0,x.ch1,x.ch0,x.ch1);运行结果:i=60501ch0=101,ch1=141ch0=A,ch1=a0100000101100001ch0ch1p=q;分配内存空间函数malloc作者张旭仟 版权所有 欢迎盗版结构指针变量说明的一般形式为char name20;每个结点之间物理上可以是不连续的。功能释放ptr所
34、指向的一块内存空间,ptr是一个任意类型的指针变量,它指向被释放区域的首地址。int month;例:union datachar ch;表示动态分配100个字节的内存空间,并强制转换为字符数组类型,函数的返回值为指向该字符数组的指针,把该指针赋予指针变量pc。int num;作者张旭仟 版权所有 欢迎盗版如:struct student例如char*pc;pc=(char*)malloc(100);结构体的成员名可以与程序中的变量名相同,二者不代表同一对象。char name20;下图为一简单链表的示意图char sex;通过以上3步就可以实现在链表中由指针q指向的结点后面插入p所指向的结点
35、。作者张旭仟 版权所有 欢迎盗版char ch;作者张旭仟 版权所有 欢迎盗版printf(Sex=%cnScore=%fnn,pstu-sex,pstu-score);printf(Sex=%cnScore=%fnn,pstu-sex,pstu-score);根据数据项的值检索链表中的结点100102 WangLi F 20 98 Beijing分配内存空间函数 callocint year;int num;char name20;struct datefloat score;num,(*pstu).union data作者张旭仟 版权所有 欢迎盗版作者张旭仟 版权所有 欢迎盗版结构指针变量
36、说明的一般形式为应先定义结构体类型,再定义结构体变量char sex;int num;char name20;stu1,stu2;void insert(stud*p)char stuname20;int age;printf(Sex=%cnScore=%fnn,pstu-sex,pstu-score);作者张旭仟 版权所有 欢迎盗版 int num;head=creat(3);unionfloat f;分配内存空间函数mallocscanf(%s,fullname);struct student stu1=112,“Wang Lin”,M,19,“200 Beijing Road”;stu1
37、.作者张旭仟 版权所有 欢迎盗版stu1=112,“Wang Lin”,M,19,“200 Beijing Road”;char ch;#include stdlib.用typedef定义的类型ltypedef的功能l用自定义的名字为已有的数据类型重新命名l类型定义后,可以与已有的类型一样使用l定义形式 ltypedef type name;l其中ltypedef 是类型定义语句关键字ltype 为已有数据类型名lname是用户自定义的类型名例:typedef int INTEGER;typedef float REAL;例 INTEGER a,b,c;REAL f1,f2;int a,b,c;float f1,f2;类型定义后,就可以与已有的类型一样使用