第十一章 结构体与共用体结构体结构体是一种构造数据类型把不同类型的数据组合成一个整体--自定义数据类型结构体类型定义
struct 结构体名 ]
{
类型标识符 成员名;
类型标识符 成员名;
……………,
};
成员类型可以是基本型或构造型
struct关键字,
不能省略合法标识符可省,无名结构体
struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
name
num
sex
age
score
addr
2字节
2字节
20字节
1字节
4字节
30字节

…..
结构体类型定义描述结构的组织形式,不分配内存例,
先定义结构体类型,再定义结构体变量一般形式:
struct 结构体名
{
类型标识符 成员名;
类型标识符 成员名;
…………….
};
struct 结构体名 变量名表列;
结构体变量的定义
struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
struct student stu1,stu2;
例:
定义结构体类型的同时定义结构体变量一般形式,struct 结构体名
{
类型标识符 成员名;
类型标识符 成员名;
…………….
}变量名表列;例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
直接定义结构体变量
struct
{
类型标识符 成员名;
类型标识符 成员名;
…………….
}变量名表列;例 struct
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
用无名结构体直接定义变量只能一次一般形式,
结构体类型与结构体变量概念不同类型,不分配内存;变量,分配内存类型,不能赋值、存取、运算;变量,可以结构体成员名与程序中变量名可相同,不会混淆结构体可嵌套说明,
例 struct date
{ int month;
int day;
int year;
};
struct student
{ int num;
char name[20];
struct date birthday;
}stu;
num name birthdaymonth day year
例 struct student
{ int num;
char name[20];
struct date
{ int month;
int day;
int year;
}birthday;
}stu;
num name birthdaymonth day year
引用规则,结构体变量不能整体引用,只能引用变量成员成员 (分量 )运算符优先级,1
结合性,从左向右引用方式,结构体变量名,成员名结构体变量的引用例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
stu1.num=10;
stu1.score=85.5;
stu1.score+=stu2.score;
stu1.age++;
例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
printf(“%d,%s,%c,%d,%f,%s \n”,stu1); (?)
stu1={101,“Wan Lin”,?M?,19,87.5,“DaLian”}; (?)
例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
if(stu1==stu2)
…….,(?)
例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
stu2=stu1;
可以将一个结构体变量赋值给另一个结构体变量例 struct student
{ int num;
char name[20];
struct date
{ int month;
int day;
int year;
}birthday;
}stu1,stu2;
num name birthdaymonth day year
stu1.birthday.month=12;
结构体嵌套时逐级引用形式一,struct 结构体名
{
类型标识符 成员名;
类型标识符 成员名;
…………….
};
struct 结构体名 结构体变量 ={初始数据 };
例 struct student
{ int num;
char name[20];
char sex;
int age;
char addr[30];
};
struct student stu1={112,“Wang Lin”,?M?,19,“200 Beijing Road”};
结构体变量的初始化形式二:
struct 结构体名
{
类型标识符 成员名;
类型标识符 成员名;
…………….
}结构体变量 ={初始数据 };
例 struct student
{ int num;
char name[20];
char sex;
int age;
char addr[30];
}stu1={112,“Wang Lin”,?M?,19,“200 Beijing Road”};
形式三:
struct
{
类型标识符 成员名;
类型标识符 成员名;
…………….
}结构体变量 ={初始数据 };
例 struct
{ int num;
char name[20];
char sex;
int age;
char addr[30];
}stu1={112,“Wang Lin”,?M?,19,“200 Beijing Road”};
结构体数组的定义的三种形式:
形式一,
struct student
{ int num;
char name[20];
char sex;
int age;
};
struct student stu[2];
num
name
sex
age
num
name
sex
age
stu[0]
stu[1]
25B
结构体数组形式二,
struct student
{ int num;
char name[20];
char sex;
int age;
}stu[2];
num
name
sex
age
num
name
sex
age
stu[0]
stu[1]
25B
形式三,
struct
{ int num;
char name[20];
char sex;
int age;
}stu[2];
num
name
sex
age
num
name
sex
age
stu[0]
stu[1]
25B
结构体数组初始化分行初始化,
struct student
{ int num;
char name[20];
char sex;
int age;
};
struct student stu[ ]={{100,“Wang Lin”,?M?,20},
{101,“Li Gang”,?M?,19},
{110,“Liu Yan”,?F?,19}};
全部初始化时可省顺序初始化,
struct student
{ int num;
char name[20];
char sex;
int age;
};
struct student stu[ ]={100,“Wang Lin”,?M?,20,
101,“Li Gang”,?M?,19,
110,“Liu Yan”,?F?,19};
例 struct student
{ int num;
char name[20];
char sex;
int age;
}stu[ ]={{……},{……},{……}};
例 struct
{ int num;
char name[20];
char sex;
int age;
}stu[ ]={{……},{……},{……}};
struct student
{ int num;
char name[20];
char sex;
int age;
}stu[3];
stu[1].age++;
strcpy(stu[0].name,”ZhaoDa”);
结构体数组引用引用方式,结构体数组名 [下标 ].成员名例,统计候选人选票
struct person
{ char name[20];
int count;
} leader[3]={“Li”,0,“Zhang”,0,”Wang“,0};
void main()
{ int i,j; char leader_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++;
}
for(i=0;i<3;i++)
printf("%5s:%d\n",leader[i].name,leader[i].count);
}
name count
Li
Zhang
Wang
0
0
0
指向结构体变量的指针
定义形式,struct 结构体名 *结构体指针名 ;
例 struct student *p;
存放结构体变量在内存的起始地址结构体和指针
num
name
sex
age
stu
pstruct student{ int num;
char name[20];
char sex;
int age;
}stu;
struct student *p=&stu;
使用结构体指针变量引用成员形式
(*结构体指针名 ).成员名 结构体指针名 -->成员名 结构体变量名,成员名指向运算符优先级,1
结合方向:从左向右例 int n;
int *p=&n;
*p=10;? n=10
struct student stu1;
struct student *p=&stu1;
stu1.num=101;? (*p).num=101
void main()
{ struct student
{ long int num;
char name[20];
char sex;
float score;
}stu_1,*p;
p=&stu_1;
stu_1.num=89101;
strcpy(stu_1.name,"Li Lin");
p->sex='M';
p->score=89.5;
printf("\nNo:%ld\nname:%s\nsex:%c\nscore:%f\n",
(*p).num,p->name,stu_1.sex,p->score);
}
例如:
指向结构体数组的指针例:指向结构体数组的指针
struct student
{ int num;
char name[20];
char sex;
int age;
}stu[3]={{10101,"Li Lin",'M',18},
{10102,"Zhang Fun",'M',19},
{10104,"Wang Min",'F',20}};
void main()
{ struct student *p;
for(p=stu;p<stu+3;p++)
printf("%d%s%c%d\n",p->num,p->name,p->sex,p->age);
}
num
name
sex
age
stu[0]
p
stu[1]
stu[2]
p+1
用结构体变量的成员作参数 ----值传递用指向结构体变量或数组的指针作参数 ----地址传递用结构体变量作参数 ----多值传递,效率低用指向结构体的指针作函数参数
struct data
{ int a,b,c; };
main()
{ void func(struct data);
struct data arg;
arg.a=27; arg.b=3; arg.c=arg.a+arg.b;
printf("%d %d %d\n",arg.a,arg.b,arg.c);
func(arg);
printf("%d %d %d\n",arg.a,arg.b,arg.c);
}
void func(struct data parm)
{ printf("%d %d %d\n",parm.a,parm.b,parm.c);
parm.a=18; parm.b=5; parm.c=parm.a*parm.b;
printf("%d %d %d\n",parm.a,parm.b,parm.c);
}
arga,27b,3
c,30
(main)
(func)
parm
a,27
b,3
c,30
arg
a,27
b,3
c,30
(main)
(func)
parm
a,18
b,5
c,90
arg
a,
b,3
c,30
ai )例:用结构体变量作函数参数
a,27
b,3
c,30
ai )
值传递
struct data
{ int a,b,c; };
main()
{ void func(struct data *parm);
struct data arg;
arg.a=27; arg.b=3; arg.c=arg.a+arg.b;
printf("%d %d %d\n",arg.a,arg.b,arg.c);
func(&arg);
printf("%d %d %d\n",arg.a,arg.b,arg.c);
}
void func(struct data *parm)
{ printf("%d %d %d\n",parm->a,parm->b,parm->c);
parm->a=18; parm->b=5; parm->c=parm->a*parm->b;
printf("%d %d %d\n",parm->a,parm->b,parm->c);
}
arg
a,18
b,5
c,90
(main)
arg
a,27
b,3
c,30
(main)例,用结构体指针变量作函数参数
arga,27b,3
c,30
(main)
(func)
parm****
arga,18b,5
c,90
(func)
parm****
链表 ──结构指针的应用
1.链表结构链表是一种常用的,能够实现动态存储分配的数据结构 。
( 1) 头指针变量 head── 指向链表的首结点 。
( 2) 每个结点一般由 2个域组成:
1) 数据域 ── 存储结点本身的信息 。
2) 指针域 ── 指向后继结点的指针 。
( 3) 尾结点的指针域置为,NULL( 空 ),,作为链表结束的标志 。
1356
A
1475
B
NULL
C1249
head 1249 1356 1475
2.C语言对链表结点的结构描述在C语言中,用结构体类型来描述结点结构。例如:
struct grade
{ char no[7]; /*学号 */
int score; /*成绩 */
struct grade *next; /*指针域 */
};
( 1) 创建链表是指,从无到有地建立起一个链表,即往空链表中依次插入若干结点,并保持结点之间的前驱和后继关系 。
( 2)检索操作是指,按给定的结点索引号或检索条件,
查找某个结点。如果找到指定的结点,则称为检索成功;
否则,称为检索失败。
3.对链表的基本操作
( 3) 插入操作是指,在结点 ki-1与 ki之间插入一个新的结点 k?,使线性表的长度增 1,且 ki-1与 ki的逻辑关系发生如下变化:
插入前,ki-1是 ki的前驱,ki是 ki-1的后继;插入后,
新插入的结点 k?成为 ki-1的后继,ki的前驱 。
( 4) 删除操作是指,删除结点 ki,使线性表的长度减 1,
且 ki-1,ki和 ki+1之间的逻辑关系发生如下变化:
删除前,ki是 ki+1的前驱,ki-1的后继;删除后,ki-1成为 ki+1的前驱,ki+1成为 ki-1的后继。
3.对链表的基本操作基本思路:
首先向系统申请一个结点的空间,然后输入结点数据域的
( 2个 ) 数据项,并将指针域置为空 ( 链尾标志 ),最后将新结点插入到链表尾 。 对于链表的第一个结点,还要设置头指针变量 。
代码中的 3个指针变量 head,newone和 tail的说明如下:
( 1) head── 头指针变量,指向链表的第一个结点,用作函数返回值 。
( 2) newone── 指向新申请的结点 。
( 3) tail── 指向链表的尾结点,用 tail->next=new,实现将新申请的结点,插入到链表尾,使之成为新的尾结点 。
创建一个链表
#include <stdlib.h>
#define LEN sizeof(struct grade)
struct grade
{ char no[7];
int score;
struct grade *next;
};
/*create()函数,创建一个具有头结点的动态单链表 */
struct grade *create( void )
{ struct grade *head=NULL,*newone,*tail;
int count=0; /*链表中的结点个数 (初值为 0)*/
for( ; ; )
{newone=(struct grade *)malloc(LEN); /*申请新结点空间 */
printf("the number of student No.%d,",count+1);
scanf("%6s",newone ->no);
if(strcmp(newone->no,"000000")==0)
{ free(newone); /*释放最后申请的结点空间 */
break;
}
printf("the score of the student No.%d:",count+1);
scanf("%d",&newone->score);
count++; /*结点个数加 1*/
newone->next=NULL; /*置新结点的指针域为空 */
/*将新结点插入到链表尾,并设置新的尾指针 */
if(count==1) head= newone; /*是第一个结点,置头指针 */
else tail->next= newone; /*非首结点将新结点插入到链表尾 */
tail= newone; /*设置新的尾结点 */
}
return(head);
}
41
#include <stdio.h>
#include <stdlib.h>
#define LEN sizeof(struct student)
struct student
{
long num;
int score;
struct student *next;
};
对链表的综合操作:建立链表 create()、输出链表 print()、
删除某个结点 delete()、插入某个结点 insert()
main()
{ struct student *creat(int n);
void print(struct student *head);
struct student *del(struct student *head,long num);
struct student *insert(struct student *head,struct
student *stud)
struct student *head,stud; int n; long del_num;
printf("\nPlease input the length of list:");
scanf("%d",&n);
head=creat(n);
print(head);
printf("\nPlease input the delete number:");
scanf("%ld",&del_num);
head=del(head,del_num);
insert(head,stud);
print(head);
}
struct student *creat(int n)
{
struct student *head,*p1,*p2;
int i;
head=NULL;
for(i=1;i<=n;i++)
{ p1=(struct student *) malloc (LEN);
printf("Number "); scanf("%ld",&p1->num);
printf("score "); scanf("%d",&p1->score);
if(i==1) head=p1;
else p2->next=p1;
p2=p1;
}
p2->next=NULL;
return(head);
}
void print(struct student *head)
{
struct student *p;
p=head;
printf("NumberScore\n");
while(p!=NULL)
{
printf(" %ld %5d",p->num,p->score);
p=p->next;
printf("\n");
}
}
struct student *del(struct student *head,long num)
{ struct student *p1,*p2;
p1=head;
while(p1!=NULL)
{
if(p1->num == num)
{
if(p1 == head) head=p1->next;
else p2->next=p1->next;
}
p2=p1;
p1=p1->next;
}
return(head);
}
struct student *insert(struct student *head,struct
student *stud)
{ struct student *p0,*p1,*p2;
p1=head; p0=stud;
if(head==NULL) /*空链表 */
{head=p0;p0->next=NULL;}
else /*非空链表 */
{ while( (p0->num > p1->num) && (p1->next!=NULL) )
{ p2=p1; p1=p1->next;}
if( p0->num < p1->num )
{ if( head==p1 ) head=p0;
else p2->next=p0;
p0->next=p1; }
else { p1->next=p0; p0->next=NULL;}
}
return(head);
}
构造数据类型,也叫联合体使几个不同类型的变量共占一段内存 (相互覆盖 )
– 共用体类型定义定义形式,union 共用体名{
类型标识符 成员名;
类型标识符 成员名;
…………….
};例 union data
{ int i;
char ch;
float f;
}; f
ch
i 类型定义不分配内存共用体
union data
{ int i;
char ch;
float f;
}a,b;
union data
{ int i;
char ch;
float f;
};
union data a,b,c,*p,d[3];
union
{ int i;
char ch;
float f;
}a,b,c;
共用体变量的定义
f
ch
i
b
共用体变量定义分配内存,
长度 =最长成员所占字节数
f
ch
i
a
共用体变量任何时刻只有一个成员存在共用体变量引用共用体指针名 ->成员名共用体变量名,成员名 (*共用体指针名 ).成员名
union data
{ int i;
char ch;
float f;
};
union data a,b,c,*p,d[3];
a.i a.ch a.f
p->i p->ch p->f
(*p).i (*p).ch (*p).f
d[0].i d[0].ch d[0].f
不能引用共用体变量,只能引用其成员例 union
{ int i;
char ch;
float f;
}a;
a=1; (?)
引用规则例 a.i=1;
a.ch='a';
a.f=1.5;
printf("%d",a.i); (?编译通过,运行结果不对 )
共用体变量中起作用的成员是最后一次存放的成员不能在定义共用体变量时初始化例 union
{ int i;
char ch;
float f;
}a={1,?a?,1.5}; (?)
可以用一个共用体变量为另一个变量赋值例 float x;
union
{ int i; char ch; float f;
}a,b;
a.i=1; a.ch=?a?; a.f=1.5;
b=a; (?)
x=a.f; (?)
例,将一个整数按字节输出
01100001 01000001
低字节高字节
01000001
01100001
ch[0]
ch[1]
运行结果:
i=60501
ch0=101,ch1=141
ch0=A,ch1=a
main()
{ union int_char
{ int i;
char ch[2];
}x;
x.i=24897;
printf("i=%o\n",x.i);
printf("ch0=%o,ch1=%o\n
ch0=%c,ch1=%c\n",
x.ch[0],x.ch[1],x.ch[0],x.ch[1]);
}
区别,存储方式不同联系,两者可相互嵌套
struct node
{ char ch[2];
int k;
}a;
union node
{ char ch[2];
int k;
} b;
achk
bch k
变量的各成员同时存在任一时刻只有一个成员存在结构体与共用体例 11.12 结构体中嵌套共用体
name num sex job class position
Li
Wang
1011
2086
F
M
S
T
501
prof
struct
{ int num;
char name[10];
char sex;
char job;
union
{ int class;
char position[10];
}category;
}person[2];
1,枚举类型的定义,enum 枚举类型名 {取值表 };
例如,enum weekdays {Sun,Mon,Tue,Wed,Thu,Fri,Sat};
2,枚举变量的定义 ── 与结构变量类似
( 1) 间接定义例如,enum weekdays workday;
( 2) 直接定义例如,enum {Sun,Mon,Tue,Wed,Thu,Fri,Sat} workday;
枚举型
( 1) 枚举型仅适应于取值有限的数据 。
例如,1周7天,1年12个月 。
( 2) 取值表中的值称为枚举元素,其含义由程序解释 。
例如,不是因为写成,Sun”就自动代表,星期天,。
事实上,枚举元素用什么表示都可以 。
( 3) 枚举元素作为常量是有值的,定义时的顺序号 (从0开始 ),
所以枚举元素可以进行比较,比较规则是:序号大者为大 。
例如,上例中的 Sun=0,Mon=1,…… Sat=6,所以 Sun<Mon,Sat
最大 。
( 4) 枚举元素的值也是可以人为改变的:在定义时由程序指定 。
例如,如果 enum weekdays {Sun=7,Mon=1,Tue,Wed,Thu,
Fri,Sat};则 Sun=7,Mon=1,从 Tue=2开始,依次增1 。
3.说明功能:用自定义名字为已有数据类型命名类型定义简单形式,typedef type name;
类型定义语句关键字用 typedef定义类型已有数据类型名用户定义的类型名例 typedef int INTEGER;
例 typedef float REAL;
类型定义后,与已有类型一样使用例 INTEGER a,b,c;
REAL f1,f2;
int a,b,c;
float f1,f2;
说明,
typedef 没有创造新数据类型
typedef 是定义类型,不能定义变量
typedef 与 define 不同
define是预编译时处理时简单字符置换
typedef是编译时处理为已有类型命名例 typedef int INTEGER;
例 typedef float REAL;
按定义变量方法先写出定义体,如 int i;
将变量名换成新类型名,如 int INTEGER;
最前面加 typedef,如 typedef int INTEGER;
用新类型名定义变量,如 INTEGER i,j;
typedef定义类型步骤例 定义数组类型
int a[100];
int ARRAY[100];
typedef int ARRAY[100];
ARRAY a,b,c;
int a[100],b[100],c[100];
例 定义函数指针类型
int (*p)( );
int (*POWER)( );
typedef int (*POWER)( );
POWER p1,p2;? int (*p1)(),(*p2)();
例 定义结构体类型
typedef struct date
{ int month;
int day;
int year;
}DATE;
DATE birthday,*p
struct date
{ int month;
int day;
int year;
}birthday,*p;
例 定义指针类型
char *str;
char *STRING;
typedef char *STRING;
STRING p,s[10];
char *p;
char *s[10];
类型定义可嵌套例 typedef struct club
{ char name[20];
int size;
int year;
}GROUP;
typedef GROUP *PG;
PG pclub;
GROUP为结构体类型
PG为指向 GROUP的指针类型
GROUP *pclub;
struct club *pclub;
实验十
实验指导书实验九的第 3题,源文件命名为 sy10-
1.cpp上传;
实验指导书实验十一的第 1题,源文件命名为 sy10-
2.cpp上传。
作业:
教材 Pg.296 11.1与 11.2合并 11.3