




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第9章结构体和共用体
结构体和共用体(也称联合)是程序设计中常用的数据类型,常用于描述实际问题中具有多个不同数据成员的一类实体。9.1概述
9.2结构体与结构体类型变量9.3结构体数组9.4指向结构体类型数据的指针9.5动态存储分配与链表9.6共用体9.7枚举类型9.8用Typedef定义类型9.9应用实例——学生成绩管理系统9.1概述家庭住址
(字符串)身份证号
(长整型)性别
(字符型)年龄
(整型)姓名
(字符串)学号
(长整型)
在实际应用中,人们经常需要将不同类型的数据作为一个整体来处理。
比如:要描述一个学生的基本情况,就需要记录他的学号、姓名、年龄、性别、身份证号、家庭住址等信息。9.2结构体与结构体类型变量
在C语言中,结构体是不同数据类型的集合。
在使用结构体这种数据类型之前,必须要先对其进行定义,对结构体的定义包括结构体类型和结构体变量的定义两部分。9.2.1结构体类型的定义声明一个结构体类型的一般形式为:struct结构体名{成员列表};structstudent{longnum;charname[20];intage;charsex;longcertificate;charaddress[40];};E-mail(字符串)电话号码(长整型)邮编(长整型)家庭住址(字符串)部门(字符串)姓名(字符串)【例9.1】如果通讯地址表由下面的项目构成:structaddr{charname[20]; /*姓名*/chardepartment[30]; /*部门*/charaddress[30]; /*家庭住址*/longbox; /*邮编*/longphone; /*电话号码*/charemail[30]; /*E-mail*/};9.2.2结构体类型变量的定义
应当定义结构体类型的变量,并在其中存放具体的数据。定义方法有以下三种:
(1)先定义结构体类型再定义结构体变量。structstudent{intnum;charname[20];floatscore;};structstudentboy1,boy2;(2)在定义结构体类型的同时定义结构体变量。一般形式为:struct结构名{
结构体成员表列}变量名表列;structstudent{intnum;charname[20];floatscore;}boy1,boy2;(3)直接定义结构体类型变量。一般形式为:struct{
结构体成员表列}变量名表列;struct{intnum;charname[20];floatscorce;}boy1,boy2;9.2.2结构体类型变量的定义有关结构体类型需要说明的是:1)结构体类型与变量的概念。只能对变量进行操作(赋值、存取或运算),而不能对一个结构体类型进行操作。编译时,只对变量分配内存空间,对结构体类型不分配内存空间。2)对结构体中的成员可以单独使用,它的作用与地位相当于普通变量。3)结构体的成员也可以是一个结构体变量,从而构成嵌套结构。structdate/*说明一个结构体类型*/{intmonth;intday;intyear;};structstudent{intnum;charname[20];charsex;intage;structdatebirthday;/*birthday是structdate类型*/charaddress[20];}student1,student2;numnamesexagebirthdayaddressmonthdayyear4)结构体中的成员名可以与程序中的变量名相同,但二者代表不同的对象。9.2.3结构体变量的引用结构体变量也可以像其他类型的变量一样赋值、存取或运算,所不同的是结构体变量必须以成员作为基本单位来参与。结构体成员的表示方法为:结构体变量名.成员名例如:student1.num表示第一个人的学号;student2.sex表示第二个人的性别。关于引用结构体成员有几点说明:(1)如果结构体成员本身又属于一个结构体类型,则需要若干个成员运算符,一级一级来找到最低的成员,且只能对最低级的成员进行赋值、存取或运算student1.monthstudent1.birthday.daystudent1.birthday.year(2)结构体变量中各成员的使用方法与普通的简单类型变量完全相同。student1.sex=student2.sex;student1.num++;(3)不能将结构体变量作为一个整体进行输入和输出。假设已将student1和student2定义为结构体类型structstudent的变量,并且各成员已赋值,则不能这样引用:printf("%d,%s,%c,%d,%f,%s\n",student1);只能对结构体变量中的成员分别进行输入、输出或赋值。例如:student1.num=1001;仅在以下两种情况下,可以把结构体变量作为一个整体来访问(引用)。1)可以对结构体变量进行整体赋值,例如:student1=student2;/*将student2中的所有内容赋值给student1*/2)取结构体变量的地址,例如:printf("%x",&student1);/*输出student1的地址*/对结构体变量的整体操作只限于赋值操作和参数传递,而且要求结构体变量的类型必须完全一致。【例9.2】结构体变量的赋值并输出其值。#include"stdio.h"voidmain(){structstu{intnum;char*name;charsex;floatscore;}boy1,boy2;boy1.num=102;boy1.num="zhangping";printf("inputsexandscore:");scanf("%c%f",&boy1.sex,&boy1.score);boy2=boy1;printf("number=%d\nname=%s\n",boy2.num,);printf("sex=%c\nscore=%.2f\n",boy2.sex,boy2.score);}程序的运行结果:inputsexandscore:M96number=102name=zhangpingsex=Mscore=96.009.2.4结构体变量的初始化与普通变量一样,对结构体变量可以在变量定义时指定初始值,也就是给结构体变量的各个成员项赋初值。【例9.3】外部结构变量初始化#include"stdio.h"structstu{intnum;char*name;charsex;floatscore;}boy2,boy1={102,"zhangping",'M',96.00};voidmain(){boy2=boy1;printf("number=%d\nname=%s\n",boy2.num,);printf("sex=%c\nscore=%f\n",boy2.sex,boy2.score);}程序的运行结果:inputsexandscore:M96number=102name=zhangpingsex=Mscore=96.00【例9.4】静态结构变量初始化#include"stdio.h"voidmain(){staticstructstu{intnum;char*name;charsex;floatscore;}boy2,boy1={102,"zhangping",'M',96.00};boy2=boy1;printf("number=%d\nname=%s\n",boy2.num,);printf("sex=%c\nscore=%f\n",boy2.sex,boy2.score);}不能在结构体内赋初值。例如,以下的初始化工作就是错误的:structstudent{longintnum=102;charname[20]="zhangping";charsex='M';floatscore=96.00;}boy1;9.3结构体数组结构体变量也可以构造成数组,称为结构体数组。每个结构体数组元素都是一个结构体变量,都含有结构体的各个成员项。每个数组的元素在内存中的地址是按照数组下标的顺序连续的。结构体数组的定义方法,例如:structstudent{intnum;charname[20];floatscore;}student1[45];结构体数组的初始化:structstudent{intnum;charname[20];floatscore;}a[2]={{1001,"Zhang",85},{1002,"Wang",86}};【例9.3】计算学生的平均成绩和不及格人数。structstudent{intnum;charname[20];floatscore;}student1[5]={{1001,"Liping",55},{1002,"Zhangping",80},{1003,"Wangfang",75},{1004,"Chenglin",82},{1005,"Wuyong",94}};main(){inti,c=0;floataverage,s=0;for(i=0;i<5;i++){s+=student1[i].score; if(student1[i].score<60)c+=1; }average=s/5; printf("average=%f\ncount=%d\n",average,c);}【例9.4】建立同学通讯录。#include"stdio.h"#defineNUM3structmen{charname[20];charphone[10];};main(){structmenman[NUM];inti;for(i=0;i<NUM;i++){printf("inputname:");gets(man[i].name);printf("inputphone:");gets(man[i].phone);}printf("name\t\tphone\n\n");for(i=0;i<NUM;i++)printf("%s\t\t%s\n",man[i].name,man[i].phone);}【例9.5】对候选人得票的统计程序,设有3个候选人,选民每次输入一个候选人的姓名,要求最后输出各人的得票结果。分析:设一个数组,有3个元素,每个元素中的信息应该包括候选人的姓名(字符型)和得票数(整型),用结构体数组来实现。#include"stdio.h"#include"string.h"structperson /*声明结构体类型structperson*/{charname[20]; /*候选人姓名*/intcount; /*得票数*/}leader[3]={"Li",0,"Zhang",0,"Fun",0}; /*定义结构体数组*/voidmain(){inti,j;charleader_name[20]; /*定义字符数组*/for(i=1;i<=10;i++){scanf("%s",leader_name); /*输入候选人的姓名*/for(j=0;j<3;j++)if(strcmp(leader_name,leader[j].name)==0)leader[j].count++;}printf("\nResult:\n");for(i=0;i<3;i++)printf("%5s:%d\n",leader[i].name,leader[i].count);}9.4指向结构体类型数据的指针结构体变量或数组也是内存中的对象,可以通过指针进行访问。指向结构体变量的指针称为结构体指针,实质上是指向结构体变量的首地址,其逻辑上加1,等于加一个结构体类型所占的字节数,即加一个结构体的长度。结构体指针必须先说明,然后指向同类型的对象再通过指针引用所指对象的各个成员项。9.4.1指向结构体变量的指针指向结构体变量的指针变量的定义的一般形式为:struct结构体名*结构体指针变量名例如:strcutstud_score{intnum;charname[20];floatscore;};structstud_score*spoint;结构体变量访问的一般形式为:(*结构体指针变量).成员名或为:结构体指针变量->成员名例如:(*spoint).num或为:spoint->num【例9.8】指向结构体变量的指针的应用。structstudent{intnum;charname[20];floatscore;}student1={1001,"Zhang",75.5},*spoint;main(){spoint=&student1;printf("Number=%d,Name=%s,",student1.num,);printf("Score=%f\n",student1.score);printf("Number=%d,Name=%s,",(*spoint).num,(*spoint).name);printf("Score=%f\n",(*spoint).score);printf("Number=%d,Name=%s,",spoint->num,spoint->name);printf("Score=%f\n",spoint->score);}运行结果如下:Number=1001,Name=Zhang,Score=75.500000Number=1001,Name=Zhang,Score=75.500000Number=1001,Name=Zhang,Score=75.500000结构体变量.成员名(*结构体指针变量).成员名结构体指针变量->成员名这三种表示结构成员的形式是完全等效的。9.4.2指向结构体数组的指针指针变量也可以指向一个结构体数组,这时结构体指针变量的值是整个结构体数组的首地址。【例9.9】指向结构体数组的指针变量的应用实例。structstudent{intnum;charname[20];floatscore;}student1[5]={{1001,"Liping",55},{1002,"Zhangping",80},{1003,"Wangfang",76.5},{1004,"Chenglin",62},{1005,"Wuyong",94}};说明:(1)如果pa=student1,表示指针pa指向结构体数组student1的第1个元素。student1+i和pa+i均表示数组第i个元素的地址,数组元素个成员的引用形式为:(student1+i)->name,(student1+i)->num和(pa+i)->name,(pa+i)->num等。student1+i和pa+i与student1[i]意义相同。(2)如果指针变量pa指向数组的某一个元素,则pa++指向下一个元素。(3)一个结构指针变量虽然可以用来访问结构体变量或结构体数组元素的成员,但是,不能使它指向一个成员。也就是说不允许取一个成员的地址来赋予它。右边的赋值是错误的:pa=&student1[0].num;正确的:pa=student1;/*赋予数组首地址*/或是pa=&student1[2];/*赋予2号元素的地址*/。main(){structstudent*pa;printf("NO\tName\t\tScore\t\n");for(pa=student1;pa<student1+5;pa++)printf("%d\t%s\t%f\t\n",pa->num,pa->name,pa->score);getch();}9.4.3结构体指针变量作为函数的参数将一个结构体变量的值传递给另一个函数,有3种方法:(1)用结构体变量的成员作参数。用法和普通变量作实参是一样的,属于“值传递”方式。应当注意实参与形参的类型保持一致。(2)结构体变量作实参。在ANSIC标准中允许用结构体变量作参数进行整体的传送,但这种传送方式要经全部成员逐个传送,特别是成员为数组时将会使传送的时间和空间开销很大,严重地降低了程序的效率。因此,一般较少采用这种方法。(3)用指向结构体变量(或数组)的指针作为实参,将结构体变量(或数组)的地址传给形参。用指针变量作函数参数进行传送,这时由实参传向形参的只是地址,减少了时间和空间的开销。【例9.7】输入10个用户的信息,调用函数change将原电话号码中259开头的电话号码改为255开头。#include"stdio.h"#definemax10structuser{intnum;charname[20];chartelephone[8];};voidchange(structuseru){inti;for(i=0;i<10;i++)if((u[i].telephone[0]=='2')&&(u[i].telephone[1]=='5')&&(u[i].telephone[2]=='9'))u[i].telephone[2]=='5';}
main(){structuseruser1[10];inti;for(i=0;i<10;i++){printf("inputnum:");scanf("%d",&user1[i].num);printf("inputname:");scanf("%s",&user1[i].name);printf("inputtelephone:");scanf("%s",&user1[i].telephone);}change(user1);for(i=0;i<10;i++)printf("num:%d,name:%s,telephone:%s\n",user[i].num,user[i].name,user[i].telephone);}【例9.11】计算一组学生的平均成绩和不及格人数。用结构指针变量作函数参数编程。structstu{intnum;char*name;floatscore;}student[5]={{101,"Liping",45},{102,"Zhangping",62.5},{103,"Hefang",92.5},{104,"Chengling",87},{105,"Wangming",58}};main(){structstu*pa;voidave(structstu*pa);pa=student;ave(pa);}voidave(structstu*pa){intc=0,i;floatave,s=0;for(i=0;i<5;i++,pa++){s+=pa->score;if(pa->score<60)c+=1;}printf("s=%f\n",s);ave=s/5;printf("average=%f\ncount=%d\n",ave,c);}9.4.4结构体与函数的类型结构体除了可以作为函数的参数外,函数的返回值也可以是结构体变量或是指向结构体变量的指针。当函数的返回值是一个结构体变量时,称该函数为一个结构体类型函数,其一般形式为:struct结构体名函数名(形参表){函数体}【例9.12】结构体中包含了一个学生的学号、姓名、成绩等成员项。结构体数组中包含一个班45人的基本信息,通过函数输入结构体数组的每个元素各个成员项的值。计算出成绩的平均值,输出成绩小于平均值的学号、姓名、分数。#include"stdio.h"#defineNUM45structstu{intnum;charname[20];floatscore;}main(){structstuinp();inti;floatave=0.0;structstuws[NUM];for(i=0;i<NUM;i++){ws[i]=inp();ave+=ws[i].score;}ave/=NUM;for(i=0;i<NUM;i++)if(ws[i].score<ave)printf("num:%dname:%sscore:%f\n",ws[i].num,ws[i].name,ws[i].score);}structstuinp(){charstr[20];structstustemp;printf("\ninputnum:");scanf("%d",&stemp.num);printf("\ninputname:");gets();printf("\ninputscore");scanf("%f",&stemp.score);return(stemp);}函数的类型说明方式为:struct结构体名*函数名(形参表)
【例9.13】结构体指针型函数举例。结构体中包含一个学生的学号、姓名、成绩。结构体数组中包含一个班45人的基本信息,输入一个学号再通过函数在结构体数组中查找,找到后函数返回数组元素的地址,没有找到返回NULL(0)。#include"stdio.h"#defineNULL0structstu{intnum;charname[20];floatscore;}main(){structstu*findp(intnumber,structstu*sp);structstustudent[45]={{1001,"Liping",55},{1002,"Zhangping",80},{1003,"Wangfang",75},{1004,"Chenglin",82},……{1045,"Wuyong",94}};intfnum;/*存放待查找学号*/inti;structstu*sap;printf("Enterthenumber:");scanf("%d",&fnum);sap=findp(fnum,student);if(sap->num!=NULL){printf("number:%d\n",sap->num);printf("name:%s\n",sap->name);printf("score:%f\n",sap->score);}elseprintf("Notfound\n");}
structstu*findp(intnumber,structstu*sp){inti;structstu*stemp=NULL;for(i=0;i<45;i++,sp++)if(sp->num==number){stemp=sp;break;/*找到后终止循环*/}return(stemp);}9.5.1链表的概念在链表数据中,任意一个数据项都包含如下内容:数据域指针域
每个数据项称为一个结点,每个结点不仅存放了数据,而且指明了下一项数据到哪里去取。数据域存放该数据项的内容,指针域存放下一数据项地址。9.5动态存储分配与链表
链表是一种常见的数据结构,它动态地进行存储分配,并且可以方便而又简单地进行数据输入、删除等操作。2000Data12500Data22300Data3NULLN1N2N3200025002300head结构体中必须有一个成员项是指向相同类型结构体的指针,称为引用自身的结构体。如:structstu{intnum;char*name;floatscore; /*三项数据域*/structstu*next; /*指向相同类型结构体的指针,指针域*/};9.5.2动态存储分配(1)分配内存空间函数malloc。函数原型:(类型说明符*)malloc(size);功能:在内存的动态存储区中分配一块长度为“size”字节的连续区域。函数的返回值为该区域的首地址。“类型说明符”表示把该区域用于何种数据类型。“(类型说明符*”表示把返回值强制转换为该类型指针。size是一个无符号数。例如:pc=(char*)malloc(100);表示分配100个字节的内存空间,并强制转换为字符数组类型,函数的返回值为指向该字符数组的首指针,把该指针赋予指针变量pc。(2)分配内存空间函数calloc。函数原型:(类型说明符*)calloc(n,size);功能:calloc也用于分配内存空间,在内存动态存储区中分配n块长度为size字节的连续区域。函数的返回值为该区域的首地址。“(类型说明符*)”用于强制类型转换。calloc函数与malloc函数的区别仅在于一次可以分配n块区域。例如:ps=(structstu*)calloc(2,sizeof(structstu));其中,sizeof(structstu)是求stu的结构长度。该语句的意思是:按stu的长度分配2块连续区域,强制转换为stu类型,并把其首地址赋予指针变量ps。(3)释放内存空间函数free。函数原型:free(void*ptr);功能:释放ptr所指向的一块内存空间,ptr是一个任意类型的指针变量,它指向被释放区域的首地址。被释放区域应是由malloc或calloc函数所分配的区域。【例9.11】分配一块区域,输入一个学生数据。#include"stdlib.h"#include"stdio.h"main(){structstu{intnum;char*name;floatscore;}*ps;ps=(structstu*)malloc(sizeof(structstu));ps->num=102;ps->name="Zhangping";ps->score=62.5;printf("Number=%d\nName=%s\n",ps->num,ps->name);printf("Score=%f\n",ps->score);free(ps);}9.5.3建立和输出链表所谓动态建立链表是指程序执行过程中从无到有地建立链表,将一个一个新生成的结点顺次连接入已建立的链表上,上一个结点的指针域存放下一个结点的起始地址,并给各结点的数据域赋值。所谓输出链表是将链表上各结点的数据域中的值依次输出,直到链表的结束NULL。【例9.12】以3个结构体变量为结点建立一个简单的链表并输出。#include"stdio.h"structnode{intdata;structnode*next;};voidmain(){structnodea,b,c,*head,*p;head=&a;/*头结点指向a的结点*/a.data=5;a.next=&b;/*a结点指向b结点*/b.data=10;b.next=&c;/*b结点指向c结点*/c.data=15;c.next=NULL;/*c结点指向尾结点NULL*/p=head;/*使p指向a结点*/while(p!=NULL){printf("%d-->",p->data);/*输出指针p所指向结点的数据*/p=p->next;/*使p指向下一个结点*/}printf("NULL\n");}程序的输出结果:5-->10-->15-->NULL9.5.3链表的基本操作链表的基本操作包括,建立并初始化链表,遍历访问链表(包括查找结点,输出结点等),删除链表中的结点,在链表中插入结点。链表的各种基本操作的步骤如下:1.建立链表①建立头结点(或定义头指针变量);②读取数据;③生成新结点;④将数据存入节点的数据域中;⑤将新结点连接到链表中(将新结点地址赋给上一个结点的指针域连接到链表);⑥重复步骤②~⑤,直到尾结点NULL为止。2.遍历访问链表输出链表即顺序访问链表中各结点的数据域,方法是:从头结点开始,不断地读取数据和下移指针变量,直到尾结点为止。【例9.13】建立并输出一个学生的成绩表(假设学生成绩表中只含姓名和成绩)。#include<stdio.h>#include<malloc.h>typedefstructstudent{charname[20];intscore;structstudent*next;}ST,*STU;STUcreatelink(intn){inti;STUp,q,head;if(n<=0)return(NULL);head=(STU)malloc(sizeof(ST));printf("inputdatas:\n");scanf("%s%d",head->name,&head->score);p=head;for(i=1;i<n;i++){q=(STU)malloc(sizeof(ST));scanf("%s%d",q->name,&q->score);p->next=q;p=q;}p->next=NULL;return(head);}
voidlist(STUhead){STUp=head;while(p!=NULL){printf("%s\t%d\n",p->name,p->score);p=p->next;}}voidmain(){STUh;intn;printf("inputnumberofnode:");scanf("%d",&n);h=createlink(n);list(n);}程序运行结果:inputnumberofnode:4↙inputdatas:A60↙B70↙C80↙D90↙A60B70C80D903.在链表的某结点前插入一个结点①开辟一个新结点并将数据存入该结点的数据域;②找到插入点结点;③将新结点插入到链表中,将新结点的地址赋值给插入点上一个结点的指针域,并将插入点的地址存入新结点的指针域。【例9.17】编写一个函数,在例9.16中建立的链表的前面插入一个结点。#include<stdio.h>#include<malloc.h>typedefstructstudent{charname[20];intscore;structstudent*next;}ST,*STU;STUcreatelink(intn){inti;STUp,q,head;if(n<=0)return(NULL);head=(STU)malloc(sizeof(ST));printf("inputdatas:\n");scanf("%s%d",head->name,&head->score);p=head;for(i=1;i<n;i++){q=(STU)malloc(sizeof(ST));scanf("%s%d",q->name,&q->score);p->next=q;p=q;}p->next=NULL;return(head);}
voidlist(STUhead){STUp=head;while(p!=NULL){printf("%s\t%d\n",p->name,p->score);p=p->next;}}STUincreasenodel(STUhead){STUs;s=(STU)malloc(sizeof(ST));printf("inputnewnodedatas:");scanf("%s%d",s->name,&s->score);s->next=head;head=s;return(head);}voidmain(){STUh;intn;printf("inputnumberofnode:");scanf("%d",&n);h=createlink(n);list(h);h=increasenodel(h);list(h);getch();}程序运行结果:inputnumberofnode:3↙inputdatas:A60↙B70↙C80↙A60B70C80inputnewnodedatas:E100↙E100A60B70C80【例9.18】编写一个函数,在例9.16中建立的链表的第i个结点之后插入一个结点。#include<stdio.h>#include<malloc.h>typedefstructstudent{charname[20];intscore;structstudent*next;}ST,*STU;STUcreatelink(intn){inti;STUp,q,head;if(n<=0)return(NULL);head=(STU)malloc(sizeof(ST));printf("inputdatas:\n");scanf("%s%d",head->name,&head->score);p=head;for(i=1;i<n;i++){q=(STU)malloc(sizeof(ST));scanf("%s%d",q->name,&q->score);p->next=q;p=q;}p->next=NULL;return(head);}STUincreasenode2(STUhead,inti){STUs,p,q;intj=0;if(i<0)returnNULL;s=(STU)malloc(sizeof(ST));printf("inputnewnodedatas:");scanf("%s%d",s->name,&s->score);if(i==0){s->next=head;head=s;return(head);}q=head;while(j<i&&q!=NULL){j++;p=q;q=q->next;}if(j<i)returnNULL;p->next=s;s->next=q;return(head);}voidlist(STUhead){STUp=head;while(p!=NULL){printf("%s\t%d\n",p->name,p->score);p=p->next;}}voidmain(){STUh;intn,i;printf("inputnumberofnode:");scanf("%d",&n);h=createlink(n);list(h);printf("inputnewnodenumber:");scanf("%d",&i);h=increasenode2(h,i);list(h);getch();}程序运行结果:inputnumberofnode:3↙inputdatas:A60↙B70↙C80↙A60B70C80inputnewnodenumber:2↙inputnewnodedatas:E100↙A60B70E100C804.删除链表中的一个结点①找到要删除结点的前驱结点;②将要删除结点的后驱结点的地址赋给要删除结点的前驱结点的指针域;③将要删除节点的空间释放。【例9.19】编写一个函数,在例9.16中建立的链表中删除链表的首结点函数。#include<stdio.h>#include<malloc.h>typedefstructstudent{charname[20];intscore;structstudent*next;}ST,*STU;STUcreatelink(intn){inti;STUp,q,head;if(n<=0)return(NULL);head=(STU)malloc(sizeof(ST));printf("inputdatas:\n");scanf("%s%d",head->name,&head->score);p=head;for(i=1;i<n;i++){q=(STU)malloc(sizeof(ST));scanf("%s%d",q->name,&q->score);p->next=q;p=q;}p->next=NULL;return(head);}voidlist(STUhead){STUp=head;while(p!=NULL){printf("%s\t%d\n",p->name,p->score);p=p->next;}}STUdeletenodel(STUhead){STUs;if(head!=NULL)printf("afterdeletedthefirstnode:\n");s=head;head=s->next;free(s);}voidmain(){STUh;intn;printf("inputnumberofnode:");scanf("%d",&n);h=createlink(n);list(h);h=deletenodel(h);list(h);}程序运行结果:inputnumberofnode:4↙inputdatas:A60↙B70↙C80↙D90↙A60B70C80D90inputnewnodenumber:2↙afterdeletedthefirstnode:B70E100C80【例9.20】编写一个函数,在例9.16中建立的链表中删除链表的第i个结点的函数。#include<stdio.h>#include<malloc.h>typedefstructstudent{charname[20];intscore;structstudent*next;}ST,*STU;STUcreatelink(intn){inti;STUp,q,head;if(n<=0)return(NULL);head=(STU)malloc(sizeof(ST));printf("inputdatas:\n");scanf("%s%d",head->name,&head->score);p=head;for(i=1;i<n;i++){q=(STU)malloc(sizeof(ST));scanf("%s%d",q->name,&q->score);p->next=q;p=q;}p->next=NULL;return(head);}voidlist(STUhead){STUp=head;while(p!=NULL){printf("%s\t%d\n",p->name,p->score);p=p->next;}}
STUdeletenode2(STUhead,inti){STUp,s;intj;if(i<1)returnNULL;if(i==1){if(head!=NULL){s=head;head=s->next;free(s);}return(head);}s=head->next;p=head;j=2;while(j<i&&s!=NULL){j++;p=s;s=s->next;}if(j<i)returnNULL;p->next=s->next;free(s);return(head);}voidmain(){STUh;inti,n;printf("inputnumberofnode:");scanf("%d",&n);h=createlink(n);list(h);printf("whichnodeyouwanttodelete:");scanf("%d",&i);h=deletenode2(h,i);list(h);}程序运行结果:inputnumberofnode:4↙inputdatas:A60↙B70↙C80↙D90↙A60B70C80D90whichnodeyouwanttodelete:A60E100C809.6.1共用体的概念和定义两种类型数据在内存中所占的字节数不同,但要在同一地址开始存放。这种使几个不同的类型数据共用同一段内存的结构,称为“共用体”类型的结构,即使用共享技术,几个变量互相共享。
例如:在学校的教师和学生中填写以下表格:姓名、年龄、职业、单位等数据项的表格。“职业”一项可分为“教师”和“学生”两类,对“单位”一项学生应填入班级编号,教师应填入某系某教研室,班级可用整型量表示,教研室只能用字符类型。要求把这两种类型不同的数据都填入“单位”这个变量中,就必须把“单位”定义为包含整型和字符型数组这两种类型的变量,也就是要把一个整型量、一个字符数组存放在同一个地址开始的内存单元(“单位”这个变量)中。共用体与结构体的不同:在结构体中各成员有各自的内存空间,一个结构变量的总长度是各成员长度之和。而在共用体中,各成员共享一段内存空间,一个共用体变量的长度等于各成员中最长的长度。共用体类型的定义和共用体变量的说明之间的关系是一个共用体类型必须经过定义之后,才能把变量说明为该共用体类型。定义共用体类型的一般形式为:union共用体名
{共用体成员表列};例如:unionperdata{intclass;charoffice[10];};定义了一个名为perdata的共用体类型,它含有两个成员,一个为整型,成员名为class;另一个为字符数组,数组名为office。共用体变量的定义也有三种形式,说明如下:(1)先定义共用体类型,再定义共用体变量。unionperdata{intclass;charoffice[10];};unionperdataa,b;/*说明a,b为perdata类型*/(2)在定义共用体类型的同时定义共用体变量。unionperdata{intclass;charoffice[10];}a,b;(3)直接定义共用体类型的变量。union{intclass;charoffice[10];}a,b; 【例9.17】uniondata{inta;floatb;doublec;charch;}f1;structstu{inta;floatb;doublec;charch;}f2;main(){printf("%d,%d",sizeof(structstu),sizeof(uniondata));}程序运行结果如下:15,89.6.2共用体变量的引用对共用体成员的引用一般引用形式为:共用体变量名.成员名例如,若定义了一个共用体类型:uniondata{inti;floatf;charch;}a;则可以使用以下方式引用共用体成员并赋值:a.i=5;a.f=3.25;a.ch='a';同样,还可以定义共用体变量的指针:uniondata*p=&a;而用共用体指针变量的引用形式为:(*p).i或p->i在使用共用体类型的数据时要注意以下几点:(1)同一个内存段可以用来存放几种不同类型的成员,但在每一瞬间只能存放其中一种,而不是同时存放几种。也就是说,每一瞬间只有一个成员起作用,其他的成员不起作用,即不是同时都起作用。(2)共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后,原有的成员就失去了作用。(3)共用体变量的地址和它的各成员的地址都是同一地址。(4)不能对共用体变量名赋值,也不能企图引用变量名来得到一个值,还不能在定义共用体变量时对它初始化。(5)不能把共用体变量作为函数参数,也不能使函数带回共用体变量,但可以使用指向共用体变量的指针。(6)共用体类型可以出现在结构体类型定义中,也可以定义共用体数组。反之,结构体也可以出现在共用体类型定义中,数组也可以作为共用体成员。【例9.18】设有一个教师与学生通用的表格,教师数据有姓名、年龄、职业、教研室四项。学生有姓名、年龄、职业、班级四项。编程输入人员数据,再以表格输出。main(){struct{charname[10];intage;charjob;union{intclass;charoffice[10];}depa;}body[2];intn,i;for(i=0;i<2;i++){printf("inputname,age,jobanddepartment\n");scanf("%s%d%c",body[i].name,&body[i].age,&body[i].job);if(body[i].job=='s')scanf("%d",&body[i].depa.class);elsescanf("%s",body[i].depa.office);}
printf("name\tagejobclass/office\n");for(i=0;i<2;i++){if(body[i].job=='s')printf("%s\t%3d%3c%d\n",body[i].name,body[i].age,body[i].job,body[i].depa.class);elseprintf("%s\t%3d%3c%s\n",body[i].name,body[i].age,body[i].job,body
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 二零二五版知识产权维权代办服务合同范本
- 二零二五年度数字货币安全存储与交易服务合同
- 二零二五年智能精装修工程服务合作框架协议
- 二零二五年度橱柜销售与家居一体化服务合同
- 2025版电网基础设施投资供电协议合同范本
- 2025版环保项目合作协议保密条款制定标准
- 二零二五年度智能住宅房地产劳务施工承包合同范本
- 二零二五年酒店管理VI视觉形象设计合作协议
- 二零二五年度抵押房产买卖合同解除条件约定
- 2025年度房产中介担保贷款服务合同范本(专业版)
- 产品实现策划的方法及要求课件
- 农机金融贷可行性报告
- GB/T 32440.1-2023鞋类化学试验方法邻苯二甲酸酯的测定第1部分:溶剂萃取法
- 中国古典诗歌在国外的译介与影响
- 成人玩具筹资计划书
- 安全生产培训记录及效果评估表
- 非常好:中考经典二次函数应用题(含答案)
- 畜禽健康养殖技术
- 2016年高考英语(江苏卷)(含答案)
- 2023年西安交通大学少年班自主招生选拔测试数学试题(含答案)
- 企业品质标语(15篇)
评论
0/150
提交评论