C语言程序设计实用教程第10章.ppt_第1页
C语言程序设计实用教程第10章.ppt_第2页
C语言程序设计实用教程第10章.ppt_第3页
C语言程序设计实用教程第10章.ppt_第4页
C语言程序设计实用教程第10章.ppt_第5页
已阅读5页,还剩62页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第十章 结构体与共用体 10.1 结构体类型与结构体变量的定义 10.2 结构变量的初始化与引用 10.3 结构体数组 10.4 指向结构体类型数据的指针 10.5 结构体和函数 10.6 单链表 10.7 共用体 10.8 枚举类型 10.9 定义已有类型的别名 教学提示 前6章介绍了五种基本数据类型和指针类型,还介绍了 一种构造类型数组,它是用基本数据类型构造出来的具 有相同类型变量的集合。当要处理那些具有不同类型、而又 相互关联的一组数据时,数组就显得力不从心。本章将介绍 另外几种构造类型结构体、共用体和枚举。它们可以是 不同类型变量的集合,其中最重要的是结构体类型,它可以 方便地处理像“记录”、“链表”这样的静态和动态数据结 构。 教学目标 掌握结构体类型、结构体变量、结构体数组、结构体 指针的定义和引用方法,掌握结构体变量、结构体数组和结 构体指针变量在函数间的传递规则,能够用结构体进行链表 的简单操作,了解共用体及枚举类型的概念、定义和引用, 学会已有类型的别名定义方法。 概述 在一些复杂的数据结构中,有时需要将不同类型的数据集合 成一个有机的整体。 如:一个学生的情况纪录单可能包括学号、姓名、性别、年 龄、成绩、家庭地址等数据项。这样的整体,C语言中称为“结 构体”数据结构,简称“结构体” (structure)。 结构体是一种较为复杂而又非常灵活的构造型的数据类型。 一个结构体类型的数据可以由若干个称为成员(或域)的成分 组成。不同的结构体类型其成员不同。对于一个具体的结构体 而言,其成员的数量是固定的,这一点与数组相同,但该结构 体中各成员的数据类型可以不同,这是结构体与数组的重要区 别。 10.1 结构体类型与结构体变量的定义 10.1.1 结构体类型定义 结构体类型定义的一般形式: struct 结构体名 数据类型 数据项1; 数据类型 数据项2; 数据类型 数据项;; 其中struct是关键字,结构体成员表列也称域表,每个成员也 称结构体中的一个域。对每个成员都应进行类型说明。 例如:struct student int num; char name20; char sex; int age; float score; ; 对结构体类型定义的说明 1 结构体类型定义是由程序员根据设计需要自行定义 的,因此结构体类型可以有多种,每种结构体类型都可 以有自己的结构体名以及包含不同数目的成员。 2 若定义了一个结构体类型,那仅仅是定义类型而已 ,而不分配内存单元。例如上面已经定义了的struct student结构体类型,struct student可以用来定义一个 该类型的变量,并不意味着它的那些成员被分配了内存 空间。 3 成员名可以与程序中的变量名相同,两者不代表同 一对象。例如,程序中可以另定义变量num,它与 struct student中的num是两回事,互不干扰。 4 结构体成员类型可以是整型 、实型、字符型、数组、指针 等基本类型或构造类型,还可 以是已定义过的结构体类型。 struct date int year; int month; int day; ; struct student int num; char name20; char sex; struct date birthday; float score4; ; 练习: 定义一个学生成绩结构类型:由学号和三门成绩共4 项组成。 10.1.2 结构体变量定义 结构体类型的定义只是指出了该结构的组成情况, 表明存在有此种类型的结构模型。该结构体类型中不 能存放具体的数据,系统也不会为它分配实际的存贮 单元。为了能在程序中使用结构体类型的数据,应在 定义了某种结构体类型以后,再定义该结构体类型的 变量,以便在结构体类型的变量中存放具体的数据。 结构体变量的定义有三种形式: 结构体变量定义1 1先声明结构体类型,再定义结构体类型的变量 。 struct student int num; char name20; char sex; int age; float score4; ; struct student st1, st2; numnamesexagescore 结构体变量定义2 2在声明结构体类型的同时定义结构体类型的变量。 struct student int num; char name20; char sex; int age; float score4; st1,st2; 结构体变量定义3 3直接定义结构体类型变量。 struct int num; char name20; char sex; int age; float score4; st1,st2; 在关键字struct后省略了结构体名 。不提倡使用这种形式。 可用sizeof来计算一个结构体类型数据的长度 如:sizeof(struct student) 或 sizeof(st1) 有关结构体变量的说明 (1)结构体类型与结构体变量是两个不同的概念, 其区别如同int类型与int型变量的区别一样。 (2)结构体类型中的成员名,可以与程序中的变量 同名,它们代表不同的对象,互不干扰。 (3)定义了结构体变量后,系统会为之分配内存单 元。如上例中的st1,st2在内存中各占37个字节。可用 sizeof来计算一个结构体类型数据的长度。如: sizeof(struct student)或sizeof(st1)。 练习2 定义一个学生信息结构类型:由学号、姓名、性别和生 日共4项组成,其中生日由日期结构类型构成。 10.2 结构变量的初始化与引用 初始化就是在定义变量的同时给变量赋初值,例如: struct student int num; char name8, sex; struct date int year, month, day; birthday; float score4; st1=101, “Xu“, F, 1975, 9, 12, 83.5, 88, 75.5, 90; 在对结构体变量进行初始化时,系统是按每个成 员在结构体中的顺序一一对应赋初值的。若只对部分 成员进行初始化,则只能给前面的若干成员赋值,而 不允许跳过前面的成员给后面的成员赋值。未赋值部 分均为0值。 结构体变量的引用 1.结构体变量整体引用 如果要将结构体变量整体引用则往往只限于将一个结构体变 量直接赋值给另一个具有相同类型的结构体变量。 struct student int num; char name8, sex; struct date int year, month, day; birthday; float score4; st1=101, “,Xu“, F, 1975, 9, 12, 83.5, 88, 75.5, 90; struct student st2; st2=st1; 程序执行后变量st2中各成员的值都完全与st1各成员的值相等。 2. 结构体变量成员引用 对结构体成员的引用方式为: 结构体变量名.成员名 其中,“.”为结构体成员运算符,它的优先级处于所有 运算符优先级的最高级别 。 例如:st1.num表示st1变量中的num成员,可以对它 赋值st1.num=1001,这时st1.num就相当于一个整型数 。 结构体变量引用规则说明 1 结构体变量整体不能直接用来输入输出。如: scanf (“%d,%s,%c,%d,%f“, 但可逐个全部或部分输入输出。如: scanf(“%d%c%f”, /* 对结构体成员name赋值 */ for(i=0; inum来代替,“-”称为指向运算符 。因此,下面引用结 构体成员的几种方式完全等价: 结构体变量名.成员名(如stu.num) 结构体指针名-成员名(p-num) (*结构体指针名).成员名 ( char name10; char sex; ; main() struct student st3=101,“Xu“,M,102,“Yan“,F,103,“Ling“,F; struct student *p; printf(“No Name Sex:n “); for(p=st;pnum,p-name,p-sex); 10.5 结构体与函数 10.5.1 用数据复制方式传递结构体变量 10.5.2 用地址复制方式传递结构体变量 10.5.3 结构体数组在函数间的传递 10.5.4 结构体数据作为函数返回值 10.5.1 用数据复制方式传递结构体变量 把一个结构体变量作为普通变量来处理,例如两个 相同的结构体变量之间可以赋值,可以把一个结构体 变量作为一个参数以复制方式传递给被调函数,函数 也可以返回一个结构体类型的值。 例3 用数据复制方式传递结构体变量。 #include “stdio.h“ struct student int num; char name10; char sex; ; void display(struct student s) printf(“No Name Sexn“); printf(“%-5d %-7s %cn“,s.num,,s.sex); main() struct student st =101,“Xu“,M; display(st); 有关数据复制方式传递数据时应注意以下两点: (1)调用时实参与被调用函数定义中的形参都是结构体变量 名。 (2)形参和实参代表两个不同的结构体变量,其结构类型相 同,但运行时不同存储空间。因此,调用函数的形参不能修改 实参变量的值。 10.5.2 用地址复制方式传递结构体变量 采用地址复制方式传递结构体变量时,实参是体变 量的首地址,形参是与实参有相同结构类型的指针, 该指针用来接收传递的结构体变量的首地址。用地址 复制方式来传递结构体变量是常用的传递方式,它可 以提高运行效率。 例4 给出年、月、日,计算出它是该年的第几天。要求采用地 址复制方式。 #include “stdio.h“ struct date int year,month,day; ; int days(struct date *s) static month=0,31,28,31,30,31,30,31,31,30,31,30,31; int i,sum=s-day; for(i=1;imonth;i+) sum+=monthi; if (s-month2 return sum; main() struct date ymd; int s; printf(“nEnter year-month-day: “); scanf(“%d-%d-%d“, s=days( printf(“%d-%d-%d is this year the %d day“,p-year,p- month,p-day,s); 10.5.3 结构体数组在函数间的传递 函数间不仅可以传递一般的结构体变量,还可以传递结构体 数组。在传递结构体数组时,实参是数组名,即结构体数组的 首地址;形参是可以是数组名或者指针,它接收传递过来的数 组首地址,使它指向实参所表示的结构体数组。 例5 结构体数组在函数间的传递。 #include “stdio.h“ struct student int num; char name10; char sex; ; void show(struct student *st) struct student *p; printf(“No Name Sexn“); for(p=st;pnum,p-name,p-sex); main() struct student st3=101,“Xu“,M,102,“Yan“,F,103,“Ling“,F; show (st); 10.5.4 结构体数据作为函数返回值 函数的返回值不仅可以是一个简单变量,也可以是 一个结构体变量、结构体指针变量。 例6 函数的返回值是一个结构体变量。 #include “stdio.h“ struct student int num; char name10; char sex; ; struct student read() struct student p; printf(“n num=“);scanf(“%d“, printf(“n name=“);scanf(“%s“,);getchar(); printf(“n sex=“);scanf(“%c“, return p; void display(struct student s) printf(“ No Name Sexn“); printf(“%-5d %-7s %3cn“,s.num,,s.sex); void main() struct student st; st=read(); display(st); 注意:这段程序在TC环境下运行出错,必须要在BC或者VC环 境下运行才正确。 例7 函数的返回值是一个结构体指针变量。 #include “stdio.h“ struct student int num; char name10; char sex; ; struct student *read(struct student p,int i) return p+i; void display(struct student s) printf(“ No Name Sexn“); printf(“%-5d %5s %5cn“,s.num,,s.sex); void main() struct student st3=101,“Xu“,M,102,“Yan“,F,103,“Ling“,F; struct student *p; p=read(st,0); display(*p); 10.6 单链表 10.6.1 单链表的概述 10.6.2 单链表 10.6.3 建立链表 10.6.4 输出链表 10.6.5 插入结点 10.6.6 删除结点 10.6.1 单链表的概述 C语言程序为批量的数据集合向操作系统申请存储空间时一 般有三种模式: 一、用数组,用数组存放数据时,通过数据类型定义,数组 在程序编译期间就申请到了所要求的存储空间,因此必须事先 定义好固定的长度,并且连续存放,对于那些数组元素不确定 的数组,在定义时就得用可能的最多元素的个数来定义,实际 应用中可能会造成大的浪费。(静态存储分配方式) 二、利用C语言提供的动态内存分配函数,在需要使用到某 一批数据前分配相应数量的存储空间块,该存储块由一个指针 来标识。这个操作过程是在程序运行中完成的,这是一种半动 态的存储分配方式 三、用链表C语言中引入的一种重要的数据结构 。 链表是完全动态地进行存储分配的一种结构。它能 随时随地根据需要开辟内存单元。链表中的各元素在 内存中可以不连续存放,通过指针把它们串连成一个 整体,并且被串连的数据个数和顺序关系可以按需改 变,因此能方便迅速的插入、删除数据项。 常用的内存管理函数有以下三个: 1. 分配内存空间函数malloc 调用形式: (类型说明符 *)malloc(size) 功能:在内存的动态存储区中分配一块长度为“size”字 节的连续区域。函数的返回值为该区域的首地址。 常用的内存管理函数: 2. 分配内存空间函数 calloc 调用形式: (类型说明符*)calloc(n ,size) 功能:在内存动态存储区中分配n块长度为“size”字节的连续区 域。函数的返回值为该区域的首地址。 3. 释放内存空间函数free 调用形式: free(void *ptr); 功能:释放ptr所指向的一块内存空间,ptr是一个任意类型的指 针变量,它指向被释放区域的首地址。被释放区应是由malloc 或calloc函数所分配的区域。 10.6.2 单链表 链表有单链表、双链表和循环链表之分,本章重点介绍其中 的一种最简单也是最常用的链表:单链表 有关单链表的基本概念 链表是一种链式结构,各元素在内存中可以不是 连续存放的。 链表中的元素又称为结点,结点必定是结构体变 量,它包含两个方面的数据:一为用户要用到的实际 数据(图8-6中的A、B、C、D);二为一个表示下一 结点的首地址的指针变量(图8-6结点中不加阴影的部 分)。 单链表一般设有一个头指针变量,用来存放第一 个结点的地址,图8-6中用head表示。 单链表中尾结点的指针指向NULL(表示空地址 )。 图8-6 单链表结构图 ABC0D head 使用链表前首先要定义好该链表的结点类型,链表 的结点类型是一个结构体类型,该结构体除了包括用 户要用的实际数据成员变量外,还包括一个指向自身 类型的指针变量,往往用next给该指针变量命名,顾 名思义,next表示下一个结点的地址的意思。通常也 称这种结构体类型为自引用结构 。 单链表的结点的结构体类型定义的一般形式为: struct 结构体名 结构体其他成员表列; /* 数据域 */ struct 结构体名 指针变量名; /* 地址域 */ ; 例:一个学生链表的结点的结构体类型定义如下: struct st int num; float score; struct st *next; ; 定义了结点的类型后就可以用它来定义结点变量或指向该类 型数据的指针变量了,比如: struct st stu, *p; p可以用如下语句赋值:p= 其中:指针变量next是struct st类型 中的一个成员,是指向自身结构体 类型的指针变量。 10.6.3 建立链表 建立链表是指在程序执行的过程中从无到有的创建一个链表 ,意味着反复创建一个一个的结点,并给这些结点建立起前后 相连的关系,直到最后一个结点为止。 在C程序中用循环结构实现“反复”创建结点的过程。创建每 个结点的过程可分为三步:第一步考虑新结点空间的申请,第 二步考虑给新申请到的结点的成员赋值,第三步考虑如何把新 结点插入到链表已经建好的部分。 根据第三步提出的问题,创建单链表的方式可分为三种:第 一种方式是新结点总是插到链表已建好部分的表头前;第二种 方式是新结点总是接在链表已建好部分的表尾;第三种方式是 按结点中某个成员的顺序规则创建一个有序的链表 例如现在要建立一个学生信息链表,该链表的结点类型定义 如下: struct node int num; float score; struct node *next; ; 该结点类型名称为struct node,它包含两个数据域成员: num(学号)和score(分数)和一个地址域成员:next。 下面给出了用三种方法创建学生信息表的三个函数,三个函 数的共同点是:它们都是用循环结构实现创建过程,并约定当 输入某个学生的学号为0时,结束循环即结束创建链表。 用头插入法建立链表,即新结点总是插在最前面。 struct node* create1( ) struct node* head=NULL,*p; float f; while(1) p=(struct node*)malloc(sizeof(struct node); /* 申请新结点空间 */ scanf(“%d“, /* 从键盘赋值给结点成员num */ if(p-num=0) break; /* 若num为0结束创建过程 */ scanf(“%f“,p-score=f; /* 从键盘赋值给结点成员score */ p-next=NULL; /* 给结点地址成员赋空值 */ p-next=head; /* 将新结点插到表头前 */ head = p; /* 使新结点成为新的表头 */ return head; /* 返回链表头指针 */ 10.6.4 输出链表 输出链表各结点的值只要知道链表头结点的地址, 也就是知道head头指针的值,然后设一个指针p指向 第一个结点,输出该结点的数据域数据后使p的指向 后移一个结点,继续输出数据并重设p指针,直到p指 向空地址为止。使指针p后移的操作可用语句: p=p-next; 实现,因为当前p指向的结点的地址成员p-next 存储的正是p的后继结点的地址 。 void print(struct node *head) struct node *p; p=head; printf (“Information of list as follows:n“); while (p!=NULL) printf(“%d %.1fn“,p-num,p-score); p=p-next; /* 使指针p指向下一结点 */ printf (“Finished printing!n“); 10.6.5 插入结点 插入结点的操作是在链表已经创建成功的情况下进 行的,插入结点的函数的参数应包含:结点将要插入 的链表的头指针,要插入结点的学号和分数,在指定 的学号之后插入该结点。 首先要在链表中查找有没有指定的学号,有则在其 后插入,没有则在链表的最后面插入。 struct node* insert(struct node *head,int id,int num,float score) /*按指定的学号id之后插入结点*/ struct node *p,*s; p=(struct node*)malloc(sizeof(struct node); p-num=num; p-score=score; /* 参数值赋给结点数据域 成员 */ s=head; /* 找插入位置 */ while(s /*查找指定学号id的结点*/ p-next=s-next; s-next=p; /* 完成插入结点的操作 */ return head; 10.6.6 删除结点 删除结点的操作是在链表已经创建成功的情况下进行的,删 除结点的函数的参数应包含:结点将要删除的链表的头指针, 要删除结点的学号。 首先要在链表中查找有没有要删除的学号,有则删除,没有 则不用删除。 查找链表中具有某特定学号的学生的结点信息并删除它,假 设链表头指针用head表示。 struct node* delnode(struct node *head, int num) struct node *p=head, *q; if(head=NULL) /* 空链表不能执行删除操作 */ printf(“illegal operationn“);return NULL; if(head-num=num) /* 将要被删除的结点是头结点 */ head=p-next; free(p); return head; for (q=head;q-next!=NULL;q=q-next ) /* 从第二个结点开始寻找将要被删除的结点 */ p=q-next; /*说明q指向的结点在前,p指向的结 点在后*/ if(p-num=num ) /*找到了*/ q-next=p-next; /* 删除p指向的结点,使脱离链 表 */ free(p); /* 释放p指向的空间 */ return head; printf(“Not found!n“); /* 没找到要删除的结点 */ return head; 其他链表结构 带专用头结点的单链表结构 ?data1 首元结点 datai 第i个结点head 头指针 A0C0DB head 双链表结构图 单循环链表结构图 d1d2 head dn 双循环链表结构图 d1 dnd2 head 10.7 共用体 共用体的概念 与结构体定义相似,但其成员共同占用一段内存( 空间分配为其成员中最长的),采用覆盖技术,其成 员互相覆盖,这样的数据结构称为“共用体”, 或称“联合体”。显然,对于一个共用体变量,内存 中某时刻只存放着其中的一种成员。 10.7.1 共用体类型和共用体变量的定义 定义方式跟结构体相似,只是在结构体定义中的关 键字“struct”用联合关键字“union”来代替。例如: union data int i; float f; char c6; ; 共用体变量的定义 先定义类型、再定义变量 在定义类型的同时定义变量 10.7.2 共用体变量的引用 跟结构体引用成员的方式相似,共用体体也使用引 用符“.”和指针引用符“-”来应用变量成员。 共用体变量的定义 由该类型我们可以像定义结构体变量那样定义联合型变量、 指向联合型变量的指针或联合型数组。如: union data a,b,c; union data *pu= union data pa4; 10.7.2 共用体变量的引用 跟结构体引用成员的方式相似,联合体也使用引用符“.”和指 针引用符“-”来应用变量成员,如: union data a; union data *pu; pu= scanf(“%f“, printf(“%d“,pu-i); 需要注意的是,联合体成员每一时刻只有一个起作用,该成 员是最近一次对联合体存放的成员;变量不可在定义时初始化 【例9】 输入一个unsigned long型整数,写一个函数将这个整数 的前两字节与后两个字节进行交换,主函数main()进行验证。 union data unsigned long n; int b2; ; unsigned long swapbit(unsigned long k) union data d; int t; d.n=k; t=d.b0; d.b0=d.b1; d.b1=t; return d.n; main() unsigned long n; printf(“Input data: “); scanf(“%lx“, n=swapbit(n); printf(“after swaped:%lxn“,n); 10.8 枚举类型 实际应用中,有些变量的取值被限定在一个有限 的范围内,如代表星期几的变量,只可能是星期日 星期六;性别只可能是男性或女性;逻辑量只能 是真或假;有时颜色只要取红黄兰白黑五种;等等 。 为此,语言提供了一种称为“枚举”的类型。在“ 枚举”类型的定义中一一列举出所有可能的取值,被 说明为该“枚举”类型的变量取值不能超过定义的范 围。 1. 枚举类型的定义 枚举类型定义的一般形式 enum 枚举名 枚举符表列 ; 例: enum Boolean false, true; enum Day sun, mon, tue, wed, thu, fri, sat; enum Colorred, yellow, blue, white, black; enum Sexmale, female; 其中枚举符也称为枚举元素,是用户定义的标识符,这 些标识符并不自动地代表什么含义。例如,不因为写成sun ,就自动代表星期日。 2 . 枚举变量的定义 如同结构和联合一样:可先定义枚举类型再定义 该类型的变量;也可在定义枚举类型的同时定义 该类型的变量

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论