1 / 57

第 7 章 结构体和共用体

第 7 章 结构体和共用体. 7.1.1 结构体类型和结构体变量. 数据类型 : 基本类型 : 整型、字符型、浮点型 构造数据类型 : 数组 结构体 共用体 数组实质上是同一类型变量的集合 在实际应用中,一组数据往往具有 不同 的数据类型 , 在 C 语言引入 结构体 来处理这种应用. 以我们常用的通讯录为例,通讯录中的联系人一般要设置序号、姓名、年龄、性别、通信地址等数据,这些数据组合到一起共同来描述和表达联系人这个整体信息。在数据类型说明上,序号为整型;姓名应为字符型;年龄应为整型;性别应为字符型;通信地址应为字符型.

buck
Download Presentation

第 7 章 结构体和共用体

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第7章 结构体和共用体

  2. 7.1.1 结构体类型和结构体变量 数据类型: 基本类型:整型、字符型、浮点型 构造数据类型 :数组 结构体 共用体 数组实质上是同一类型变量的集合 在实际应用中,一组数据往往具有不同的数据类型 , 在 C 语言引入 结构体 来处理这种应用.

  3. 以我们常用的通讯录为例,通讯录中的联系人一般要设置序号、姓名、年龄、性别、通信地址等数据,这些数据组合到一起共同来描述和表达联系人这个整体信息。在数据类型说明上,序号为整型;姓名应为字符型;年龄应为整型;性别应为字符型;通信地址应为字符型

  4. C语言中给出了另一种构造数据类型——“结构(structure)”或叫“结构体”,“结构”是一种构造类型,它是由若干相互关联的“成员”组成的。每一个成员可以是一个基本数据类型,也可以是数组、指针,或者又是一个构造类型。结构既然是一种“构造”而成的数据类型,那么在使用之前必须先定义它的组成成分,我们叫做结构的类型。因为客观世界管理对象的多样性,构造了某个结构类型后就可以用它来说明该结构类型的变量,以便在程序设计中来引用和操纵该结构变量

  5. 7.1.2 结构类型的定义 结构类型定义的一般形式为: struct 结构类型名 {成员列表}; 成员列表由若干个成员组成,每个成员都是该结构的一个组成部分。对每个成员也必须作类型说明,其形式为: 类型说明符 成员名; 成员名的命名应符合标识符的书写规定。

  6. 例如定义一个通讯录的联系人结构类型: struct person { long num; char name[30]; int age; char sex; char address[200]; };

  7. 结构类型说明里包含指针变量 如果将联系人的姓名用字符指针来说明的结构如下: • struct person    {        long num; char *name; • int age;        char sex; • char address[200]; };

  8. 7.1.3 结构变量的定义 • 1)先定义结构类型,再说明结构变量。如:struct person{        long num;        char name[30]; • int age;        char sex;        char address[200];}; •  struct person ab1,ab2;定义两个结构类型为person的结构变量ab1,ab2。

  9. 2)在定义结构类型的同时说明结构变量。例如:struct person    {        long num;        char name[30]; • int age;        char sex;        char address[200];}ab1,ab2;

  10. 3)直接说明结构变量。例如:struct    {        long num;        char name[30]; • int age;        char sex;        char address[200];}ab1,ab2;

  11. 结构体内存布局

  12. 结构体长度 • 结构变量的总长度为各个成员长度的总和。我们一般用 sizeof (结构类型名) 这个库函数来获取结构变量在内存实际所占字节的总长度。如取通讯录联系人结构的长度的语句为: • sizeof (struct person);

  13. 结构嵌套定义 • 通讯录联系人结构的嵌套定义:先定义一个联系方式结构: • struct contact{        char telephone[20];        char fax[20];        char email[20];    };

  14.  struct person    {        long num;        char name[30]; • int age;        char sex;        char address[200]; • struct contact lxfs;}ab1;

  15. 嵌套结构布局

  16. 7.2   结构变量成员的引用方法 • 7.2.1 结构变量的引用引用结构变量成员的一般形式是: • 结构变量名.成员名例如上面定义的联系人结构变量ab1,ab2:ab1.name        即第一个联系人的姓名ab2.age          即第二个联系人的年龄成员本身又是一个结构的引用方法,用.运算符逐级访问结构的成员. • 例如:ab1.lxfs.email

  17. 7.2.2 结构变量的赋值 • 【例7.1】给结构变量赋值并输出其值。 • #include <string.h>main(){   struct person    {        long num;        char name[30]; • int age;        char sex;        char address[200];

  18. struct person ab1,ab2;    ab1.num=1;    strcpy(ab1.name,“Zhao Jun”);    printf(“input age and sex\n”);    scanf(“%d %c”,&ab1.age,&ab1.sex);    ab2=ab1;   printf("Number=%ld\nName=%s\n" ab2.num,ab2.name);   printf("age=%d\nsex=%c\n",ab2.age,ab2.sex);

  19. 7.3  结构变量的初始化 • 【例7.2】对结构变量初始化。main(){ • struct person    {        long num;        char name[30]; • int age;        char sex;        char address[200];}ab1={1,“Gao Hong",38,’M’, “Beijing Haidian”};

  20. 7.4   结构体数组 • .4.1 结构数组的定义和初始化: • 例如: • struct person • { • long num; • char name[30]; • int age; • char sex; • char address[200]; • } • struct person abook[10];

  21. 【例7.3】输出通讯录中的联系人的平均年龄. • struct person    {        long num;        char name[30]; • int age;        char sex;        char address[200]; }abook[3]={             {1,"Xu Chong",25,"F",”Beijing Chaoyang Distinct ”},             {2,"Tao Ning",26,"F",”Shanghai Fudan University”},             {3,”Liu Qiang”,35,”M”,”Shenzhen Shitong CO.,LTD”} • };

  22. void main() { int i; int avg,sum=0; for(i=0;i<3;i++) {sum+=abook[i].age;} avg=sum/3; printf(“average=%d\n”,avg); }

  23. 7.5  结构体指针 • 结构指针变量说明的一般形式为:struct 结构名 *结构指针变量名例如,在前面的例题中定义了person 这个结构类型,如要说明一个指向person的指针变量pabook,可写为:struct person *pabook; struct person ab1; •     pabook=&ab1是正确的,而:pabook=&person是错误的。

  24. 结构指针变量访问成员 • 其访问的一般形式为:(*结构指针变量).成员名或为:结构指针变量->成员名例如:(*pabook).name或者:pabook->name

  25. 7.5.2 指向结构体数组的指针 • 结构体指针变量可以指向一个结构体数组,这时结构体指针变量的值是整个结构数组的首地址。结构指针变量也可指向结构数组的一个元素,这时结构指针变量的值是该结构数组元素的首地址。如果psa为指向结构数组的指针变量,则psa也指向该结构数组的0号元素,psa+1指向1号元素,psa+i则指向i号元素。这与普通数组的情况是一致的。

  26. 【例7.5】用指向结构体数组的指针输出结构体数组中的元素。struct person • { long num; • char name[30]; • int age; • char sex; • char address[200]; • }abook[3]={ • {1,"Xu Chong",25,'F',"Beijing Chaoyang Distinct"}, • {2,"Tao Ning",26,'F',"Shanghai Fudan University"}, • {3,"Liu Qiang",35,'M',"Shenzhen Dongxing CO.,LTD"} };

  27. void main() • { • int i; • struct person *psa; • printf("Num\t\tName\t\t\tage\t\tsex\t\t\n"); • psa=abook; • for(i=0;i<3;i++) • { • printf("%ld\t\t%s\t\t%d\t\t%c\t\t\n",psa->num,psa->name,psa->age,psa->sex); • psa++; • } • }

  28. 应该注意的语句是psa++,每次psa自增后自动跳过一个结构类型的长度,指向下一个结构变量的首地址,这样才能正确输出结构变量的成员。应该注意的语句是psa++,每次psa自增后自动跳过一个结构类型的长度,指向下一个结构变量的首地址,这样才能正确输出结构变量的成员。 • 如: • 当psa+0 指向 abook[0] 即 {1,"Xu Chong",25,'F',"Beijing Chaoyang Distinct"}的首地址; • 当psa+1指向 abook[1] 即 {2,"Tao Ning",26,'F',"Shanghai Fudan University"}的首地址;当psa+2指向 abook[2] 即 {3,"Liu Qiang",35,'M',"Shenzhen Dongxing CO.,LTD"}的首地址;

  29. 7.5.3   结构体在函数传递中的应用 • 【例7.6】计算通讯录中联系人的平均年龄和统计年龄小于30岁的人数。用结构指针变量作函数参数编程。struct person • { long num; • char name[30]; • int age; • char sex; • char address[200]; • }abook[3]={ • {1,"Xu Chong",25,'F',"Beijing Chaoyang Distinct"}, • {2,"Tao Ning",26,'F',"Shanghai Fudan University"}, • {3,"Liu Qiang",35,'M',"Shenzhen Dongxing CO.,LTD"}};

  30. void main() • { • struct person *psa; • void average(struct person *inps); • psa=abook; • average(psa); • } • void average(struct person *inps) • {struct person *tpsa; • int c=0,i; • int avg,sum=0; • tpsa=inps;

  31. for(i=0;i<3;i++) • { • sum+=tpsa->age; • if(tpsa->age<30) c+=1; • } • avg=sum/3; • printf("average=%d\n persons which age less than thirty count=%d\n",avg,c); • }

  32. 7 .6 动态存储分配 • 1) 分配内存空间malloc函数 函数原型:void*malloc(unsigned int size); • 函数功能:在内存的动态存储区中分配一块长度为"size"字节的连续区域。函数的返回值为该区域的首地址。若分配失败(系统不能提供所需内存),则返回NULL。因malloc的返回类型是void *,需要把返回值强制转换为需要的数据类型指针,比如申请内存用来处理结构类型,那么就要强制转换为结构类型。例如: char *p;          p=(char *)malloc(200*sizeof(char));

  33. 如前我们定义的结构通讯录联系人结构体,如果动态分配结构变量的存储空间,可用以下语句实现:如前我们定义的结构通讯录联系人结构体,如果动态分配结构变量的存储空间,可用以下语句实现: • struct person *pab; • pab= (struct person*) malloc (sizeof(struct person));

  34. 分配内存空间calloc函数 • calloc 是另一个用于分配内存空间的函数。 • 函数原型:void*calloc(unsigned int n,unsigned int size); • 函数功能:在内存动态存储区中分配n块长度为“size”字节的连续区域。函数的返回值为该区域的首地址。calloc函数与malloc 函数的区别仅在于一次可以分配n块size 大小的区域。例如: • struct person *pab; • pab= (struct person*) calloc (2,sizeof(struct person));

  35. 7.7 用结构和指针处理链表

  36. 图中,第0个结点称为头结点,它存放有第一个结点的首地址,它没有数据,只是一个指针变量。以下的每个结点都分为两个域,一个是数据域,存放各种实际的数据,如序号num,姓名name,年龄age, 性别sex等;另一个域为指针域,存放下一结点的首地址。链表中的每一个结点都属于同一种结构类型。头节点是链表的重要节点,链表的各种操作都是从头节点开始进行的。

  37. 结点定义 • 一个存放通讯录联系人结点应为以下结构:struct person    {   long num;         char name[30]; • int age;         char sex;         char address[200]; • struct person * next; };

  38. 7.7.2建立链表 【例7.8】建立一个有三个结点的链表,存放通讯录数据. • struct person • { long num; • char name[30]; • struct person * next; } • struct person *createlist(int n) { struct person *head,*cur,*tail; /*head为头结点;cur为新建的结点;tail为尾结点*/ int i; for(i=0;i<n;i++) • { cur=(struct person *) malloc(sizeof(struct person)); /*动态申请建立一个新结点*/

  39. if (cur==NULL) • { printf("memory malloc failure"); • exit(0); } • printf("please input number and name\n"); • scanf("%d,%s",&cur->num,cur->name); • if(i==0) tail=head=cur; /*第一个节点*/ • else tail->next=cur; /*建立中间结点*/ • cur->next=NULL; • tail=cur; } • return(head); /*函数返回新建链表的头结点*/ }

  40. 7.7.3 输出链表 • 【例7.9】输出链表数据的函数 • void output_list (struct person *head) • { • struct person *h; • h=head; • while(h!=NULL) • { • printf("%d,%s\n",h->num,h->name); • h=h->next; • } • }

  41. 7.7.4 插入操作 • 设在通讯录链表中,各联系人结点按照num(序号)由小到大顺序存放,当新建一个联系人信息时,把结点cur插入链表。用指针cur指向待插入结点,设把cur插在m2结点之前,m1结点之后(如下页图)。 • 插入算法要点如下: • 找到应插入的位置。 • 1.在m2之前、m1之后插入cur。 • 2.将cur插入第一个结点之前。 • 3.将cur插入表尾结点之后。

  42. 7.7.5 删除结点 • 删除一个结点的算法要点如下: • 找到需要删除的结点,用cur指向它。并用m1指向cur的前一个结点。 • 1.要删除的结点是头结点。 • 2.要删除的结点不是头结点。 • 设在通讯录链表中删除序号为num的结点,以表头指针head和需要删除的结点的num(序号)为参数,返回删除后的链表表头

  43. 7.8 共用体 • 7.8.2 共用体类型的定义 • 定义共用体类型的关键是 “union”。同结构类型的定义方式相似,共用体类型的一般形式为: • union 共用体类型名{成员列表};成员可以是基本数据类型,也可以是数组,指针,以及其他构造类型。

  44. union data • {char c; • int i; • float f; • }; 共用体与结构体不同的是:结构体类型是异址的,而共用体类型是同址的。也就是说,结构体长度是各个成员长度之和,而共用体所有成员共享内存的一个区域(首地址相同),共用体的长度是成员列表中最大长度的成员长度。

  45. 7.8.3 共用体变量的定义 • 定义类型后说明变量 • union data • {char c; • int i; • float f; • }; • union data u1,u2;

  46. 7.8.4 共用体变量成员的引用方法 • 1).运算符 • 在一般共用体变量中引用成员也是用.运算符 • union data u1; • u1.i=12; • u1.f=3.4; • 2)->运算符 • 如果共用体变量是指向共用体类型的指针,那么用->来访问成员。 • union data *p; • p->i=12; • p->f=3.4;

  47. 【例7.13】演示共用体成员之间赋值的覆盖形式【例7.13】演示共用体成员之间赋值的覆盖形式 • union data • {char c; • int i; • float f; }; • void main() • { union data u1; • u1.c=‘a’; • u1.i=65; • printf(“%c”,u1.i); } /*输出结果:A*/ • 程序运行结果可以看出,最后赋值的f 将覆盖点先前赋值的变量i。

  48. 7.9  枚举类型 • 在实际编程中,有些变量的取值被限定在一个有限的范围内,例如性别只有男、女,一个星期内只有七天,一年只有十二个月等。C语言提供了一种称为“枚举”的构造类型。“枚举”就是将变量可能的值一一列举出来。变量的值只能取列举出来的值之一。应该说明的是,实际上枚举类型的元素为固定的常量的集合。

More Related