570 likes | 787 Views
第 7 章 结构体和共用体. 7.1.1 结构体类型和结构体变量. 数据类型 : 基本类型 : 整型、字符型、浮点型 构造数据类型 : 数组 结构体 共用体 数组实质上是同一类型变量的集合 在实际应用中,一组数据往往具有 不同 的数据类型 , 在 C 语言引入 结构体 来处理这种应用. 以我们常用的通讯录为例,通讯录中的联系人一般要设置序号、姓名、年龄、性别、通信地址等数据,这些数据组合到一起共同来描述和表达联系人这个整体信息。在数据类型说明上,序号为整型;姓名应为字符型;年龄应为整型;性别应为字符型;通信地址应为字符型.
E N D
7.1.1 结构体类型和结构体变量 数据类型: 基本类型:整型、字符型、浮点型 构造数据类型 :数组 结构体 共用体 数组实质上是同一类型变量的集合 在实际应用中,一组数据往往具有不同的数据类型 , 在 C 语言引入 结构体 来处理这种应用.
7.1.2 结构类型的定义 结构类型定义的一般形式为: struct 结构类型名 {成员列表}; 成员列表由若干个成员组成,每个成员都是该结构的一个组成部分。对每个成员也必须作类型说明,其形式为: 类型说明符 成员名; 成员名的命名应符合标识符的书写规定。
例如定义一个通讯录的联系人结构类型: struct person { long num; char name[30]; int age; char sex; char address[200]; };
结构类型说明里包含指针变量 如果将联系人的姓名用字符指针来说明的结构如下: • struct person { long num; char *name; • int age; char sex; • char address[200]; };
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。
2)在定义结构类型的同时说明结构变量。例如:struct person { long num; char name[30]; • int age; char sex; char address[200];}ab1,ab2;
3)直接说明结构变量。例如:struct { long num; char name[30]; • int age; char sex; char address[200];}ab1,ab2;
结构体长度 • 结构变量的总长度为各个成员长度的总和。我们一般用 sizeof (结构类型名) 这个库函数来获取结构变量在内存实际所占字节的总长度。如取通讯录联系人结构的长度的语句为: • sizeof (struct person);
结构嵌套定义 • 通讯录联系人结构的嵌套定义:先定义一个联系方式结构: • struct contact{ char telephone[20]; char fax[20]; char email[20]; };
struct person { long num; char name[30]; • int age; char sex; char address[200]; • struct contact lxfs;}ab1;
7.2 结构变量成员的引用方法 • 7.2.1 结构变量的引用引用结构变量成员的一般形式是: • 结构变量名.成员名例如上面定义的联系人结构变量ab1,ab2:ab1.name 即第一个联系人的姓名ab2.age 即第二个联系人的年龄成员本身又是一个结构的引用方法,用.运算符逐级访问结构的成员. • 例如:ab1.lxfs.email
7.2.2 结构变量的赋值 • 【例7.1】给结构变量赋值并输出其值。 • #include <string.h>main(){ struct person { long num; char name[30]; • int age; char sex; char address[200];
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);
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”};
7.4 结构体数组 • .4.1 结构数组的定义和初始化: • 例如: • struct person • { • long num; • char name[30]; • int age; • char sex; • char address[200]; • } • struct person abook[10];
【例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”} • };
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); }
7.5 结构体指针 • 结构指针变量说明的一般形式为:struct 结构名 *结构指针变量名例如,在前面的例题中定义了person 这个结构类型,如要说明一个指向person的指针变量pabook,可写为:struct person *pabook; struct person ab1; • pabook=&ab1是正确的,而:pabook=&person是错误的。
结构指针变量访问成员 • 其访问的一般形式为:(*结构指针变量).成员名或为:结构指针变量->成员名例如:(*pabook).name或者:pabook->name
7.5.2 指向结构体数组的指针 • 结构体指针变量可以指向一个结构体数组,这时结构体指针变量的值是整个结构数组的首地址。结构指针变量也可指向结构数组的一个元素,这时结构指针变量的值是该结构数组元素的首地址。如果psa为指向结构数组的指针变量,则psa也指向该结构数组的0号元素,psa+1指向1号元素,psa+i则指向i号元素。这与普通数组的情况是一致的。
【例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"} };
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++; • } • }
应该注意的语句是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"}的首地址;
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"}};
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;
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); • }
7 .6 动态存储分配 • 1) 分配内存空间malloc函数 函数原型:void*malloc(unsigned int size); • 函数功能:在内存的动态存储区中分配一块长度为"size"字节的连续区域。函数的返回值为该区域的首地址。若分配失败(系统不能提供所需内存),则返回NULL。因malloc的返回类型是void *,需要把返回值强制转换为需要的数据类型指针,比如申请内存用来处理结构类型,那么就要强制转换为结构类型。例如: char *p; p=(char *)malloc(200*sizeof(char));
如前我们定义的结构通讯录联系人结构体,如果动态分配结构变量的存储空间,可用以下语句实现:如前我们定义的结构通讯录联系人结构体,如果动态分配结构变量的存储空间,可用以下语句实现: • struct person *pab; • pab= (struct person*) malloc (sizeof(struct person));
分配内存空间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));
图中,第0个结点称为头结点,它存放有第一个结点的首地址,它没有数据,只是一个指针变量。以下的每个结点都分为两个域,一个是数据域,存放各种实际的数据,如序号num,姓名name,年龄age, 性别sex等;另一个域为指针域,存放下一结点的首地址。链表中的每一个结点都属于同一种结构类型。头节点是链表的重要节点,链表的各种操作都是从头节点开始进行的。
结点定义 • 一个存放通讯录联系人结点应为以下结构:struct person { long num; char name[30]; • int age; char sex; char address[200]; • struct person * next; };
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)); /*动态申请建立一个新结点*/
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); /*函数返回新建链表的头结点*/ }
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; • } • }
7.7.4 插入操作 • 设在通讯录链表中,各联系人结点按照num(序号)由小到大顺序存放,当新建一个联系人信息时,把结点cur插入链表。用指针cur指向待插入结点,设把cur插在m2结点之前,m1结点之后(如下页图)。 • 插入算法要点如下: • 找到应插入的位置。 • 1.在m2之前、m1之后插入cur。 • 2.将cur插入第一个结点之前。 • 3.将cur插入表尾结点之后。
7.7.5 删除结点 • 删除一个结点的算法要点如下: • 找到需要删除的结点,用cur指向它。并用m1指向cur的前一个结点。 • 1.要删除的结点是头结点。 • 2.要删除的结点不是头结点。 • 设在通讯录链表中删除序号为num的结点,以表头指针head和需要删除的结点的num(序号)为参数,返回删除后的链表表头
7.8 共用体 • 7.8.2 共用体类型的定义 • 定义共用体类型的关键是 “union”。同结构类型的定义方式相似,共用体类型的一般形式为: • union 共用体类型名{成员列表};成员可以是基本数据类型,也可以是数组,指针,以及其他构造类型。
union data • {char c; • int i; • float f; • }; 共用体与结构体不同的是:结构体类型是异址的,而共用体类型是同址的。也就是说,结构体长度是各个成员长度之和,而共用体所有成员共享内存的一个区域(首地址相同),共用体的长度是成员列表中最大长度的成员长度。
7.8.3 共用体变量的定义 • 定义类型后说明变量 • union data • {char c; • int i; • float f; • }; • union data u1,u2;
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;
【例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。
7.9 枚举类型 • 在实际编程中,有些变量的取值被限定在一个有限的范围内,例如性别只有男、女,一个星期内只有七天,一年只有十二个月等。C语言提供了一种称为“枚举”的构造类型。“枚举”就是将变量可能的值一一列举出来。变量的值只能取列举出来的值之一。应该说明的是,实际上枚举类型的元素为固定的常量的集合。