690 likes | 814 Views
第七章. 结构体、共用体 和枚举类型数据. 7.1 结构体类型概述 7.2 结构体类型变量的定义与引用 7.3 结构体数组 7.4 结构体变量作为函数参数及返回值 7.5 结构体变量与指针 7.6 动态存储分配和链表 7.7 共用体类型的数据 7.8 枚举类型的数据 7.9 用 TYPEDEF 定义类型. 7.1 结构体类型概述. struct person { char name[10]; int age; char sex; long num;
E N D
第七章 结构体、共用体和枚举类型数据
7.1 结构体类型概述 • 7.2 结构体类型变量的定义与引用 • 7.3 结构体数组 • 7.4 结构体变量作为函数参数及返回值 • 7.5 结构体变量与指针 • 7.6 动态存储分配和链表 • 7.7 共用体类型的数据 • 7.8 枚举类型的数据 • 7.9 用TYPEDEF定义类型
7.1 结构体类型概述 struct person { char name[10]; int age; char sex; long num; char nation; int education; char address[20]; long tel; }; • 结构体类型是构造型数据结构 • 作为一个整体来处理多个相关的数据 • 类型标识符为两个单词组成: struct 结构体名
结构体类型的定义 struct 结构体名 { 成员项表列 }; struct person { char name[10]; int age; char sex; long num; char nation; int education; char address[20]; long tel; }; 注意不要忘记花扩号外的分号
结构体类型的特点 • 它由若干个数据项组成,每一个数据项都属于一个已有的数据类型。每一个数据项称为结构体的成员,或“域” • 结构体类型是一个抽象的类型,它只表示了“由若干个不同类型数据项组成的复合类型”,结构体类型可以有无数多种。 • 结构体类型是程序中用户自己定义的,C语言本身没有定义好的结构类型。 • 定义一个结构体类型只是表示这个类型的结构,不分配内存单元。正如类型int ,char...
7.2 结构体类型变量的定义与引用 • 定义结构体类型变量的方法(3种) • 结构体类型变量的初始化 • 结构体类型变量的引用 • 结构体的输入和输出
结构体类型变量定义(1) • 在定义了结构体类型之后,把变量定义为该类型 struct person student ,worker; 类似于 int a , b ; 注意不要写成: struct student , worker; (缺结构体类型) person student , worker; (缺struct 关键字) 结构体变量名
结构体类型变量定义(2) • 在定义一个结构体的同时定义一个或若干个结构体变量。 struct 结构体名 { 成员列表 }变量名列表; struct person { char name[10]; int age; char sex; long num; char nation; int education; char address[20]; long tel; } student, worker; 这种形式既定义了类型,同时又定义了变量 若还需要该结构类型的变量可接着用第一种方式定义,如:struct person men,women;
结构体类型变量定义(3) • 直接定义结构体变量 struct { 成员列表 }变量名列表; struct { char name[10]; int age; char sex; long num; char nation; int education; char address[20]; long tel; } student, worker; 这种形式只定义了变量,没有定义类型 若还需要该结构类型的变量不可接着用第一种方式定义,必须重新定义。
结构体类型变量定义 • 可以用已定义的另一个结构体类型来定义其成员的类型 (结构体嵌套) struct date {int month; int day; int year; }; struct { char name[10]; struct date birthday; char sex; long num; char nation; int education; char address[20]; long tel; } student, worker;
结构体类型变量定义 • 在定义了变量student和worker为struet person类型之后,它们就具有struct person结构体类型的特征。也就是说,变量student不是一个简单变量,它的值也不是一个简单的整数、实数或字符等,而是由许多个基本数据组成的复合的值。 • 可以用sizeof运算符测出一个结构体类型数据的长度, sizeof后面括弧内可以写类型名也可以变量名。 可用printf函数输出它的值: printf(“%d\n”,sizeof(struct person)); printf(“%d\n”,sizeof(student ));
结构体类型变量的初始化 • 可以在任一种定义结构类型变量的同时给结构类型变量赋初值。在初始化时,按照所定义的结构体类型的数据结构,依次写出各初始值,编译时就将它们赋给此变量中各成员。 struct person student = {“wang Li”,12,15,1974,’M’,10189341101,’H’, 12, “135 Beiging Road”,209887};
结构体类型变量的初始化 struct person { char name[10]; int age; char sex; long num; char nation; int education; char address[20]; long tel; } student={"Wang Li",12,15,1974,’M’, 10189341101,’H’, 12, “135 Beiging Road”, 209887};
结构体类型变量的初始化 • 如果一个结构体类型内又嵌套另一个结构体类型,则初始化时仍然是对各个基本类型的成员给予初值。 struct person student = {"wang Li",12,15,1974, ’M’, 10189341101,’H’, 12, “135 Beiging Road”,209887};
结构体变量的引用 • 引用结构体变量中的一个成员 结构体变量名.成员名 例: student . num student . num + 100 相当于 (student . num)+100 成员运算符级别最高
结构体变量的引用 • 嵌套的结构体类型采用逐级访问的方法 student.birthday.month; • 可以对结构体变量的成员进行有关的运算:算术、赋值、关系、逻辑运算等 例: student. num++ (自加) &student . num (取地址)
结构体变量的引用 • 相同结构的结构体变量可以互相赋值 struct stud_type student1= {“Wang Li” ,18,’M’,89101,89.5}; struct stud_type student2; student2 = student1; • 内嵌的结构体变量可以赋给另一个结构体变量 student2.birthday= student1.birthday;
不允许将一组常量直接赋给结构体变量 S2.birthday={3,20,1973}; 应分别赋给结构体变量各成员 S2.birthday.year = 1973; S2.birthday.month = 3; S2.birthday.day = 20;
结构体变量的引用 • 若在同一函数中有与结构成员同名的变量,它将在内存中另外分配存储单元,而不在结构变量范围内分配 student.num (结构体变量中的num) num (简单变量num) • 同一结构类型,不同两个变量的同一成员,代表内存中不同的存储单元,它们有不同的值,应该分别引用: 如:Student1.num和student2.num
结构体的输入和输出 • 不允许将结构体变量作为一个整体进行输入和输出。如: printf("%d\n",student); printf("%s,%d,%c,%d%d%d,%1d,%5.2f\n",student); • 只能分别对结构体的成员进行输入和输出. scanf(“%s%s%ld”, s1.name, s1.addr, &s1.num); printf(“%s,%s,%ld\n”, s1.name, s1.addr, s1.num);
struct stud { char name[20]; int age; char sex; struct date birthday; long num; float score; }; struct date { int month; int day; int year; }; 【例7.1】 main() /* c7-1.c */ { struct stud s1={“Wang Li” ,18,’M’,89101,89.5}; struct stud s2; s2=s1; printf("s1:%s,%d,%c,%d/%d/%d,%ld,%5.2f\n",s1.name, s1.age,s1.sex,s1.birthday.month,s1.birthday.day, s1.birthday.year,s1.num,s1.score); printf("s2:%s,%d,%c,%d/%d/%d,%ld,%5.2f\n",s2.name, s2.age,s2.sex,s2.birthday.month,s2.birthday.day, s2.birthday.year,s2.num,s2.score); }
7.3 结构体数组 • 一个结构体变量只能存放一个对象(如一个学生、一个职工)的一组数据。如果要存放一个班(30人)学生的有关数据就要设30个结构体变量,例如studentl,student2,…,student30,显然是很不方便的。人们自然想到使用数组。 • C语言允许使用结构体数组,即数组中每一个元素都是一个结构体变量的数组。
结构体数组的定义方法 • 有三种定义方法: (类似变量定义) • 先定义结构体类型,再用它定义结构体数组。 • 在定义结构体类型时同时定义数组。 • 直接定义结构体数组而不定义类型名。
方法1:先定义结构体类型, 再定义结构体数组 struct stu_type {char name[20]; long numl int age; char sex; float score; } …. struct stud_type student[30]; 方法2: 类型与数组同时定义 struct stud_type {…. …. } student[30]; 方法3:直接定义结构 体数组而不定义类型名 struct {…. …. } student[30];
结构体数组的初始化 struct stud_type { char name[20]; long num; int age; char sex; float score; } student[3]={{“wang Li”,80101,18,’M’,89.5}, {“Zhang Fun”,89102,19,’M’,90.5}, {“Li,Ming”,89103,20,’F’,98} }; 课本中说: 只能对静态的或外部 数组初始化.但事实上不受此限 在对结构体变量初始化时,要将每个元素的数据分别用花扩号扩起来
结构体数组的初始化 • 若初值个数与元素个数相等,则元素个数可 struct stud_type student[3]={{…},{…},{…}}; struct stud_type student[ ]={{…},{…},{…}};
结构体数组的引用 • 引用某一元素中的成员 student[i].num • 可以将一个结构体数组元素赋值给同一结构体类型的数组中另一个元素,或赋给同一类型变量. struct stu_type student[3],stud1; stud1=student[0]; student[0]=student[1]; student[1]=stud1; • 不能把结构体数组元素作为一个整体直接进行输入输出.例7-3,例7-4 结构体数组元素赋值给同一结构的结构体变量 结构体变量赋值给同一 结构的结构体数组元素 结构体数组元素赋值给另一个数组元素
【例7.3】 main() { struct { int i; char ch1; char ch2; }try; scanf("%d %c %c",&try.i,&try.ch1,&try.ch2); printf("i=%d,ch1=%d,ch2=%d\n",try.i,try.ch1,try.ch2); printf("i=%d,ch1=%c,ch2=%c\n",try.i,try.ch1,try.ch2); } scanf中输入多个类型不同的数据,易引起混乱。
【例7.4】 用gets接收输入 #include "stdlib.h" #include "stdio.h" main() { int i; char ch1,ch2,ch; char numstr[10]; gets(numstr); i=atoi(numstr); ch1=getchar(); ch=getchar(); ch2=getchar(); printf("i=%d,ch1=%c,ch2=%c\n",i,ch1,ch2); } 由于gets只能接收字符串,其它类型要用函数转换
【例7.5】输入三个学生的信息并打印出来 #include"stdio.h” /* c7-5.c */ #include"stdlib.h” struct stud_type { char name[20]; long num; int age; char sex; float score; }; /* 接下页 */
main( ) /* 续前页 */ {struct stud_type student[3]; int i; char ch, numstr[20]; for (i=0; i<3; i++) /*接收输入*/ { printf("Enter all data of students[%d] :\n", i); gets(student[i].name); gets(numstr); student[i].num=atol(numstr); gets(numstr); student[i].age=atoi(numstr); student[i].sex=getchar( ); ch=getchar( ); gets(numstr); student[i].score=atof(numstr); } printf("\nrecord name num age sex score\n"); for (i=0;i<3;i++) /*输出*/ printf("%3d %-20s%8ld %6d %3c %6.2f\n", i, student[i].name,student[i].num, student[i].age, student[i].sex, student[i].score); }
7.4 结构体变量作为函数参数及返回值 • C语言允许结构体变量作为函数参数,即将结构体变量的各个成员的值整体传送给形参(传值调用) void list (struct stud_type student) {.........} 整体传送(类型应完全一致) list ( student[i] ); (主调函数中)
例7.6 将例7.5的输出功能用一函数list实现 void list (struct stud_type student) { printf(" %-20s%10ld %6d %3c %6.2f\n", student.name, student.num, student.age, student.sex, student.score); } 结构体定义(同上,略) main( ) {struct stud_type student[3]= {{"Wang li",98101,18,'M',90.5}, {"Zhang Fun",98102,19,'M',89}, {"Li Ling",98103,20,'F',98}}; int i; printf("\n name num age sex score\n"); for (i=0;i<3;i++) list ( student[i] ); }
返回结构体类型值的函数 1.函数类型应定义为结构体类型. struct <结构体类型名> <函数名>(...) 2. 在return语句中指定结构体变量为返回值. 3. 在主调程序中,要用一个相同的结构体变量来接受返回值.
本课小结 • 能否用赋值语句对结构体变量整体赋值? • 能否对结构体变量中嵌套的结构体变量整体赋值? • 能否对结构体变量整体进行输入输出? • 能否将一个结构体变量整体传送到被调函数? • 能否将一个结构体变量整体返回到主调函数? 不能! 只能分别对结构体的成员进行输入和输出. 可以! 允许结构体变量作为函数参数被整体传送 不能! 但可以在定义时赋初值: 不能! 应分别赋给结构体变量各成员 可以 !允许函数返回一个结构体类型值, 此时函数类型应定义为相应的结构体类型
7.5 结构体变量与指针 • 指向结构体变量的指针 • 指向结构体数组的指针 • 用指向结构体变量的指针作函数参数
指向结构体变量的指针 • 可以定义一个指针变量指向一个结构体变量。所谓结构体变量的指针就是这个结构体变量所占内存单元段的起始地址。 struct stud_type student; struct stud_type *p; p=&student; (*p).name 定义指向某一结构体类型的指针变量: 用指针的方法来引用结构体的成员
结构体成员的引用方法 1、结构体变量名.成员名 student . name 2、(*p).成员名 (*p) . name 3、p->成员名 p->name
例7-9 用指向结构体变量的指针输出各成员值 #include "string.h" struct stud_type { char name[20]; long num; int age; char sex; float score; }; main() { struct stud_type student,*p; p=&student; strcpy(student.name,"Wang Li"); student.num=89101; student.age=18; student.sex='M'; student.score=89.5; printf("\nname:%s\nnumber:%ld\nage: %d\nsex:%c\nscore:%6.2f\n” , (*p).name,(*p).num,(*p).age, (*p).sex,(*p).score); }
指向结构体数组的指针 • 可以将一个指针变量指向一个结构体数组,也就是可以将该数组的起始地址赋给此指针变量 struct { int al; float b; } arr[3],*p; p=arr; p++; 例7.10:将输入3个学生的信息并打印出来的程序改用指针变量来处理(P252) 指向数组的下一个元素
指向结构体变量的指针作函数参数 例7.11 输入三个学生的信息并用list函数打印出来 (用指针做函数参数改写例7.6) #include "stdlib.h" #include "stdio.h" struct stud_type { char name[20]; long num; int age; char sex; float score; };
main( ) { struct stud_type student[3]; int i; char numstr[20]; for (i=0; i<3; i++) { printf("Enter all data of students[%d]: \n", i); gets(student[i].name); gets(numstr); student[i].num=atol(numstr); gets(numstr); student[i].age=atoi(numstr); student[i].sex=getchar( ); getchar( ); gets(numstr); student[i].score=atof(numstr); } printf("\n name\t num\t age\t sex\t score\n"); for (i=0; i<3; i++) list ( &student[i] ); } 实参:结构体数组元素首址 行参:指针 用指针做函数参数 用指针引用结构体成员 void list(struct stud_type *pt) { printf("%s\t %ld\t %d\t %c\t %6.2f\n", pt->name, pt->num, pt->age, pt->sex, pt->score); }
main() { void list(struct stud_type *pt); struct stud_type student[3],*p; int i; char ch; char numstr[20]; for(i=0, p=student; p<student+3; p++, i++) { printf("\n enter all data of student[%d]:\n",i); gets(p->name); gets(numstr);p->num=atol(numstr); gets(numstr); p->age=atoi(numstr); p->sex=getchar();ch=getchar(); gets(numstr); p->score=atof(numstr); } printf("\nname\t num\t age\t sex\t score\n"); for (p=student;p<student+3;p++) list(p); } 实参形参皆为指针 void list (struct stud_type *pt) { printf("%s\t %ld\t %d\t %c\t %6.2f\n", pt->name,pt->num,pt->age,pt->sex,pt->score); }
89101 89102 89103 89.5 75 80 3028 4016 NULL 7.6 动态存储分配和链表 • 链表的概念: 3010 3028 4016 Head 3010 结点 A 结点 B 结点 C 下一结点起址
num score next 用含指针项的结构体变量构成结点 struct stud_score { long num; float score; struct stud_score *next; };
一个最简单的链表的建立 Struct stud_score s1, s2, s3, *head; s1.num=98101; s1.score=98.5; s2.num=98102; s2.score=75; s3.num=98103; s3.score=80; head=&s1; s1.next=&s2; s2.next=&s3; s3.next=NULL;
用于动态存储分配的函数 • malloc(n) 分配 n 个字节的内存空间 • calloc(m,n) 分配 m 个 n 字节的空间 • free(*p) 释放指针p所指的存储空间 • realloc(*p,n) 将指针p所指的空间大小改为 n个字节
malloc函数 • 原形:void * malloc(unsigned int size); • 实例: char *p; float *p1; p= malloc(8); 将指针p指向新空间的起址 p1= (float *) malloc(8); 分配size个字节的内存空间并返这个空间的起始地址址; 若没有足够的内存分配则返回NULL(即0) 强制类型转换
malloc函数用法实例 struct stud_score s1, s2, s3, *new; int n; ......... n = sizeof(struct stud_score ); new = (struct stud_score *) malloc(n);
calloc函数 • 原形: void *calloc(unsigned int num,unsigned int size) • 作用:分配num个大小为size个字节的内存空间 并返这个空间的起始地址址; • 若没有足够的内存分配则返回NULL(即0)