第十一章 结构体与共用体第一节 结构体数据类型的定义与引用一般形式:
struct 结构体名
{
成员列表
} ;
类型说明 成员 1;
类型说明 成员 2;
… …
类型说明 成员 n;
不能省略例,struct student
{
int number;
char name[31];
short age;
char sex;
int grade;
char address[10];
};
/*学号 */
/*姓名 */
/*年龄 */
/*性别 */
/*年级 */
/*家庭地址 */
/*类型名 */
1.结构体类型变量的定义和引用方法 1 先定义结构,再说明结构变量
struct student
{ int number;
char name[31];
short age;
char sex;
int grade;
char address[10];
};
struct student student1,student2;
02705201
chaplin
20
M
2
shanghai
02705202
mary
19
F
2
nanjing
student1 student2
方法 2 在定义结构体的同时说明结构变量
struct 结构体名
{ 类型说明 成员 1;
类型说明 成员 2;
… …
类型说明 成员 n;
} 变量名列表 ;
struct student
{ int number;
char name[31];
short age;
char sex;
int grade;
char address[10];
} student1,student2;
方法 3 直接说明结构变量
struct
{ 类型说明 成员 1;
类型说明 成员 2;
… …
类型说明 成员 n;
} 变量名列表 ;
struct student
{ int number;
char name[31];
short age;
char sex;
int grade;
char address[10];
} student1,student2;
2)结构体类型的成员可以又是一个构造类型,
机构成了嵌套的结构注意,
如,一个地址可以由邮编和住址组成,
struct address
{ int code;
char add[10];
};
struct student
{ int number;
struct address home;
};
number
home
code add[10]
1)结构体变量可以分为局部变量和全局变量规则:
1)不能把一个结构体变量进行输入和输出
2.结构体类型数据的引用如,printf(“%d,%s,%d,%c,%d,%s”,student1);
引用方式,结构体变量名,成员名如,printf(“%d,%s,%d,%c,%d,%s”,
student1.number,
student1.name,
student1.age,
student1.sex
student1.grade,
student1.address);
规则:
2)若成员本身又是一个结构,则必须逐级找到最低级的成员才能使用如,前面提到的嵌套结构
student3.home.code 即 student3的邮编
student3.home.add 即 student3的住址
3)结构体变量成员,与相同类型的普通变量并无区别,可以像不同变量一样参与各种运算例,
student1.number=02705201;
sum=student1.number+student2.number;
student1.age++;
strcpy(student3.home.add,“nanjing”);
3.结构体变量的初始化方法 1 定义时指定初始值
struct student
{ int number;
char name[31];
short age;
char sex;
char address[10];
} a={0308,“lili”,20,? F?,2,“nanjing”};
main()
{
printf(“%d\n,%s\n,%d\n,%c\n,%s\n”,
a.number,a.name,a.age,a.sex,a.address); }
方法 2 定义时未指定初始值
struct student
{ int number;
char name[31];
short age;
char sex;
char address[10];
}a,b;
a.numbre=0308;
a.name[0]=?l?;a.name[1]=?i?;… …
a.age=20;
a.sex=?M?;
a.address[0]=?n?; a.address[1]=?a?;… …
b=a;
例,
#include,stdio.h”
main()
{
struct date
{ int year,month,day;
}today;
printf(“%d\n”,sizeof(struct date));
} 6
第二节 结构体数组
struct 结构体名
{ 成员列表
} 数组名 [长度 ];
一般形式:
例,
struct student
{ int number;
char name[31];
short age;
char sex;
char address[10];
}a[2];a[2]={
{0308,“lili”,20,? F?,,nanjing”},
{0309,“davie”,21,? M?,,shanghai”}
};
0308
davie
20
M shanghai0309
lili
21
F nanjinga[0]
a[1]
number name age sex address
习题例 1:
main()
{ struct cmplx{ int x;
int y;
}con[2]={1,3,2,7};
printf(“%d\n”,con[0].y/con[0].x*con[1].x);
}
6
习题例 2,试利用结构体类型编制一个程序,实现输入一个学生的期中和期末成绩,然后计算出其平均成绩例 3,若上题改为输入 3个学生的学号、数学期中和期末成绩,然后计算出他们各自平均成绩,
并输出成绩表习题习题例 4,设有 3个人,Li_ming,Wang_hui,Zhang_ming
分别时 18,19,20岁,用结构体类型编程,要求输出三个人中年龄居中者的年龄和姓名第三节 指向结构体的指针
1.指向结构体变量的指针如,struct st{ long num;
char name[20];
float score;
}stu{0301,”frank”,87.5};
struct st *p=&stu;
printf(“%d,%s,%f \n”,(*p).num,(*p).name,
(*p).score);
p->num,p->name
p->score);
例,
struct num
{ int a;
int b;
float f;
}n={1,3,5.0};
struct num *p=&n;
则 p->b/n.a*++p->b的值
(*p).a+p->f的值
7
6.0
例,利用指针变量,输出结构体数组中所有元素
2.指向结构体数组的指针
struct st{ … … }stu[2]={ { … },
{ … } };
main()
{
strut st *p;
for(p=stu;p<stu+2;p++)
printf(“?”,p ->.成员,? );
}
例 1:
struct ks
{ int a; int *b; }s[4],*p;
main()
{ int n=1,i;
for(i=0;i<4;i++)
{ s[i].a=n ; s[i].b=&s[i].a ; n=n+2; }
p=&s[0];
p++;
printf(“%d\n”,(++p)->a);
}
5
例 2:
struct st
{ int x; int *y; }*p;
int dt[4]={10,20,30,40};
struct st aa[4]={50,&dt[0],60,&dt[1],70,&dt[2],
80,&dt[3]};
main()
{ p=aa;
printf(“%d\n”,++p->x);
printf(“%d\n”,(++p)->x);
printf(“%d\n”,++(*p->y));
}
51
60
21
第四节 结构体指针做函数参数例,
struct n
{ int x; char c; };
main()
{ struct n a={10,?x?};
func(&a);
printf(“%d,%c\n”,a.x,a.c); }
func(struct n *b)
{ b->x=20;b->c=?y?; }
20,y
第五节 用指针处理链表
1.动态存储结构的引出
2.动态存储结构的主要思想
3.用结构体变量和指针来实现链表的方法
1)链表的概念单向循环双向循环循环链表循环双链表
2)结点:
信息域指针域
data
next
data
next
3)用结构体变量和指针表示结点的数据结构如,struct student
{ int num;
float score;
struct student *next;
};
4)实现链表的方法
0301
80.5
num
score
next
a
0302
89
b
0303
100
c
&b &c NULL
&a
head
思考题,1,各个结点是怎么构成链表?
2,没有 head头指针行不行?
3,p起什么作用?
p
3.用于动态存储分配的函数
1) malloc函数
void *malloc(unsigned size);
2) calloc函数
void *calloc(unsigned n,unsigned size);
3) free函数
void *free(void *p);
4) sizeof函数
sizeof(int)
sizeof(float)
sizeof(struct student)
4.建立动态链表例,建立 10个学生数据链表分析:
先定义结点的数据类型然后建立链表
p=q=(struct student *)malloc(sizeof(struct student));
p->next=q;
0301
80.5
head
p
q=(struct student *)malloc(sizeof(struct student));
p=q;
0302
89
q
p
q
for(n=1;n<10;n++)
{
}
NULL
0301
80.5
0302
89
head
0303
100
NULL
5.输出链表
do{
printf(“%d,%5.1f”,p->num,p->score);;
} while(p!=NULL);
p
p p
p=p->next
6.删除链表
while(p->next!=NULL)
{ q=p;
p=p->next;
if(p->num==0302);
}
n=n-1;
输入 0302(回车)删除结点
0302
89
0301
80.5
head
0303
100
NULL
p
p
q
× ×
q->next=p->next
7.插入链表 插入结点
while(p->num<r->num)
{ q=p;
p=p->next;
}
0301
80.5
head
0303
100
p
q
r
0302
89
if(p->num>=r->num)
{ ;;
}
n=n+1;
p
×
q->next=r
r->next=p
例 1:根据下图所示在以下程序的空白处填入 适当的语句
18 NULL
head data next
struct abc
{ int data;
next;
}*head;
head=(struct abc *)malloc( );
=18;
=NULL
int *
sizeof(struct abc)
head->data
head->next
例 2:以下 average函数的功能是计算链表中各考生总分平均数。请填空。
void average(struct ks *head)
{
struct ks *p;
float sum=0.0,aver;
int n=0;
p=head;
while( )
{ n++;
sum+=p->scorce;; }
aver=sum/n;
}
p->next!=NULL
p=p->next
第六节 共用体 ——联合
1.共 用体类型的定义一般形式:
union 共用体名
{ 成员列表 ;
} 共用体变量名 ;
方法 1:
union data
{ int i;
char ch;
float f;
}a,b,c;
方法 2,
union data
{ int i;
char ch;
float f;
};
union data a,b,c;
方法 3:
union
{ int i;
char ch;
float f;
}a,b,c;
四个字节
a
2.共 用体变量的引用方式 —— 先定义,后引用
1)不能引用共用体变量而只能引用它的成员如,前面定义了 a,b,c共用体变量
a.i /*引用共用体变量中的整型变量 i*/
a.ch /*引用共用体变量中的字符变量 ch*/
a.f /*引用共用体变量中的实型变量 f*/
如,不能只引用共用体变量
printf(“%d”,a);
2)共用体不能作为函数参数或函数值,但可以使用指向共用体的指针变量
3.共 用体类型的数据特点
1)共用一段内存,可以用来存放几种不同类型的成员,但每一瞬时只有一个成员起作用
2)共用体变量中前一次起作用的成员在存入新的成员后原有的成员失去意义如,a.i=1;
a.ch=?a?;
a.f=1.5; /*只有 a.f有意义,a.i,a.ch被覆盖 */
共 用体类型的数据特点
3)共用体变量和它的所有成员的地址都是同一地址
4)不能对共用体变量名赋值,也不能在定义共用体变量时对它进行初始化如 1,union data
{ int i;
char ch;
float f;
}a={1,?a?,1.5}; /*不能初始化 */
如 2,a=1; /*不能对共用体变量赋值 */
如 3,m=a; /*不能引用共用体变量名 */
共 用体类型的数据特点
5)不能把共用体变量作为函数参数,也不能使函数带回共用体变量,但可以使用指向共用体变量的指针(与结构体类似)
6)共用体数组共用体类型中可以有结构体变量作为其成员,
结构体类型中也可以有共用体变量作为其成员例 1:
union data
{
int i;
char ch;
float f[20];
}b;
b占用内存字节为 80
例 2:
main()
{ union EXAMPLE
{ struct { int x;
int y;
}in;
int a;
int b;
}e;
e.a=1;e.b=2;
e.in.x=e.a*e.b;
e.in.y=e.a+e.b;
printf(“%d,%d\n”,e.in.x,e.in.y);
} 4,8
例 3:
main()
{ union b
{
int a;
int ch[2];
}au;
au.a=129;
printf(“%d,%d\n”,au.ch[0],au.ch[1]);
}
au.a=0x12ff;
printf(“%x,%x \,,au.ch[0],au.ch[1]);
例 4:
main()
{ union pw
{
int i;
char ch[2];
}a;
a.ch[0]=13;
a.ch[1]=0;
printf(“%d\n”,a.i);
}
13
例 5:
main()
{ union u
{ char *name;
int age;
int income;
}s;
s.name=“WangLing”;
s.age=28;
s.income=1000;
printf(“%d\n”,s.age);
}
1000
例 6:
main()
{ union
{
int k;
char i[2];
}*s,a;
s=&a;
s->i[0]=0x39;
s->i[1]=0x38;
printf(“%x\n”,s->k);
}
3839
例 7,求 sizeof(struct aa)的值
struct aa
{ int r1;
double r2;
float r3;
union un{
char u1[5];
long u2[2];
}ua;
}mya;
struct
union
union
第七节 枚举类型
1.枚举,指把变量的值一一列举出来,变量的值只能限于列举出来的范围内如,
enum weekday{ sum,mon,tue,wed,thu,fri,sat};
枚举元素枚举常量枚举类型
enum weekday week_end,workday;
1.枚举数据的特点:
1)枚举元素是常量,不能给他们赋值如,sum=2;
2)枚举元素是常量,C语言编译时按定义时的顺序,使它们的值分别为 0,1,2,…,6
如,week_end=sat;
printf(“%d”,week_end);
输出结果为 6
枚举数据的特点:
3)但是,可以改变枚举元素的值如,
enum weekday
{ sum=7,mon=1,tue,wed,thu,fri,sat};
则 tue的值为
wed的值为
thu的值为
fri的值为
sat的值为
2
3
4
5
6
枚举数据的特点:
4)枚举值可以用来作比较判断比较规则:按定义时的顺序来比较,若未人为指定,则第一个枚举元素的值为 0
如,if(week_end<=fri)
if(mon>thu)
枚举数据的特点:
5)一个整数要赋值给一个枚举变量,则必须进行类型转换如 1,workday=2;
如 2,workday=(enum weekday)2;
workday=tue;
例 1:
enum coin{penny,nickel,dime,quarter,
half_dollar,dollar};
char *name[]={“penny”,“nickel”,“dime”,“quarter”,
“half_dollar”,“dollar”};
main()
{ enum coin money1,money2;
money1=dime;
money2=dollar;
printf(“%d,%d\n”,money1,money2);
printf(“%s,%s\n”,name[(int)money1],
name[(int)money2]); }
第八节 用 typedef定义类型用 typedef定义新的类型名来代替已有的类型名如 1,typedef int INTEGER;
INTEGER i,j;
int i,j;
注意,
1) typedef用来定义类型名,但不能用来定义变量
2)不能创建新类型 typedef 类型名 标识符
3)可以作为简化变量的类型说明注意,
如 1,typedef struct student{… } REC;
REC x,y,*p;
struct student x,y,*p;
例 1:
typedef int INT
main()
{ INT a,b;
a=5;b=6;
printf(“%d,%d\n”,a,b);
{ float INT;
INT=3.0;
printf(“2*INT=%.2f”,2*INT);
}
}
5,6
2*INT=6.0