Upload
noleta
View
66
Download
0
Embed Size (px)
DESCRIPTION
第十四章 结构体与共用体. 14.1 结构体 结构体是 一种 构造 数据类型 用途:把 不同类型 的数据组合成一个整体------- 自定义 数据类型 结构体类型定义. 合法标识符 可省 : 无名结构体. struct [ 结构体名 ] { 类型标识符 成员名; 类型标识符 成员名; ……………. } ;. 成员类型可以是 基本型或构造型. struct 是 关键字 , 不能省略. 2 字节. num. …. name. 20 字节. 1 字节. sex. 2 字节. age. 4 字节. score. - PowerPoint PPT Presentation
Citation preview
第十四章 结构体与共用体§ 14.1 结构体
结构体是一种构造数据类型 用途:把不同类型的数据组合成一个整体 -------自定义数据类型结构体类型定义
struct [ 结构体名 ]{ 类型标识符 成员名; 类型标识符 成员名; …………….} ;
成员类型可以是基本型或构造型struct 是关键字 ,不能省略
合法标识符可省 : 无名结构体
例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; };
name
num
sexage
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;
§ 14.2 结构体变量的定义先定义结构体类型,再定义结构体变量
一般形式:
例 #define STUDENT struct student STUDENT { int num; char name[20]; char sex; int age; float score; char addr[30]; }; 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 namebirthday
month day year
例 struct student { int num; char name[20]; struct date { int month; int day; int year; }birthday; }stu;
num namebirthday
month day year
§ 14.3 结构体变量的引用引用规则
结构体变量不能整体引用 , 只能引用变量成员可以将一个结构体变量赋值给另一个结构体变量结构体嵌套时逐级引用成员 ( 分量 ) 运算符优先级 : 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;
stu2=stu1; ( )
例 struct student { int num; char name[20]; struct date { int month; int day; int year; }birthday; }stu1,stu2;
num namebirthday
month day year
stu1.birthday.month=12;
例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2;
if(stu1==stu2)…….. ()
§ 14.4 结构体变量的初始化形式一:
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”};
§ 14.5 结构体数组结构体数组的定义
三种形式:形式一 : struct student { int num; char name[20]; char sex; int age; };struct student stu[2];
形式二 : struct student { int num; char name[20]; char sex; int age; }stu[2];
形式三 : struct { int num; char name[20]; char sex; int age; }stu[2];
num
name
sex
agenum
name
sex
age
stu[0]
stu[1]
25B
结构体数组初始化
例 struct { int num; char name[20]; char sex; int age; }stu[ ]={{……},{……},{……}};
顺序初始化 : 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 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; }str[3];
stu[1].age++;
strcpy(stu[0].name,”ZhaoDa”);
例 统计候选人选票struct person{ char name[20]; int count;}leader[3]={“Li”,0,“Zhang”,0,”Wang“,0}; 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
Ch14-1.c
struct student stu1;struct student *p=&stu1;stu1.num=101; (*p).num=101
§ 14.6 结构体和指针指向结构体变量的指针
定义形式: struct 结构体名 * 结构体指针名 ;例 struct student *p;
使用结构体指针变量引用成员形式存放结构体变量在内存的起始地址numnamesexage
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
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);}
Ch14-2.c
指向结构体数组的指针例 指向结构体数组的指针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}};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);}
numnamesexage
stu[0]
p
stu[1]
stu[2]
p+1
Ch14-3.c
用指向结构体的指针作函数参数用结构体变量的成员作参数 ---- 值传递用指向结构体变量或数组的指针作参数 ---- 地址传递用结构体变量作参数 ---- 多值传递,效率低
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("arg.a=%d arg.b=%d arg.c=%d\n",arg.a,arg.b,arg.c); printf("Call Func()....\n"); func(arg); printf("arg.a=%d arg.b=%d arg.c=%d\n",arg.a,arg.b,arg.c);}void func(struct data parm){ printf("parm.a=%d parm.b=%d parm.c=%d\n",parm.a,parm.b,parm.c); printf("Process...\n"); parm.a=18; parm.b=5; parm.c=parm.a*parm.b; printf("parm.a=%d parm.b=%d parm.c=%d\n",parm.a,parm.b,parm.c); printf("Return...\n");}
arga :27b: 3c :30
(main)
(func)
parma :27b: 3c :30
copy
arga :27b: 3c :30
(main)
(func)
parma :18b: 5c :90
arga :27b: 3c :30
(main)
arga :27b: 3c :30
(main)例 用结构体变量作函数参数14-4.c
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("arg.a=%d arg.b=%d arg.c=%d\n",arg.a,arg.b,arg.c); printf("Call Func()....\n"); func(&arg); printf("arg.a=%d arg.b=%d arg.c=%d\n",arg.a,arg.b,arg.c);}void func(struct data *parm){ printf("parm->a=%d parm->b=%d parm->c=%d\n",parm->a,parm->b,parm->c); printf("Process...\n"); parm->a=18; parm->b=5; parm->c=parm->a*parm->b; printf("parm->a=%d parm->b=%d parm->c=%d\n",parm->a,parm->b,parm->c); printf("Return...\n");}
arga :18b: 5c :90
(main)
arga :27b: 3c :30
(main)例 用结构体指针变量作函数参数
arga :27b: 3c :30
(main)
(func)parm****
arga :18b: 5c :90
(main)
(func)parm****
§ 14.7 利用结构体变量构成链表 链表是一种常用的、能够实现动态存储分配的数据结构类型。 用途:处理动态存储分配的批量数据
单向链表head
头指针 头结点头指针变量 head──指向链表的首结点。每个结点由 2个域组成:数据域──存储结点本身的信息;指针域──指向后继结点的指针。尾结点的指针域置为“ NULL (空)”,作为链表结束的标志。
例 struct grade { char no[7]; /* 学号 */ int score; /* 成绩 */ struct grade *next; /* 指针域 */ };
单向链表的建立操作步骤: (1) 读取数据 (2) 生成新结点 (3) 将数据存入结点的成员变量中 (4) 将新结点插入到链表中。
举例:编写函数 creat_slist ,建立如前页图中所示的带有头接点的单向链表。结点数据域中的数值从键盘输入,以 -1 作为输入结束标志。程序见下页:在程序中定义了有三个指针变量 h 、 s 和 r 。h 用于存放头结点的地址;S 用来指向新生成的结点;r 总是指向链表当前的尾结点。
例 typedef struct slist {int data; struct slist *next; }SLIST; SLIST *creat_slist1() {int c; SLIST *h,*s,*r; h=(SLIST *)malloc(sizeof(SLIST)); r=h; scanf (“%d”,&c); while(c!=-1) { s=(SLIST*)malloc(sizeof(SLIST)); s->data=c; r->next=s; r = s; scanf (“%d”,&c); } r->next=‘\0’; return h ; }
main(){ SLIST *head; head=creat_slist1(); . . .}
单向链表的输出void print_slist(SLIST *head){SLIST *p; p=head->next; if(p==‘\0’) printf(“Linklist is null!\n”); else { printf (“head”); do {printf(“->%d”,p->data); p=p->next; } while(p!=‘\0’); printf(“->end\n”); }}
14-5.c
在单向链表中插入结点
insert_snode (SLIST *head, int x, int y){SLIST *s,*p,*q; s=(SLIST *)malloc(sizeof(SLIST)); s->data=y; q=head; p=head->next; while((p!=‘\0’)&&(p->data!=x)) {q=p; p=p->next;} s->next=p; q->next=s;}
在值为 x的结点前,插入值为 y的结点。分析 :(1) 链表非空,值为 x的结点存在,新结点插在该结点之前 (2) 链表非空,值为 x的结点不存在,新结点插在表尾 (3) 链表为空表,新结点插在表尾
14-6.c
删除单向链表中的结点要删除单向链表中的某个结点,首先要找到等删结点的前趋结点;然后将此前趋结点的指针去指向待删结点的后继结点;最后释放被删结点所占存储空间即可。
head
头指针 头结点
q p
§ 14.8 共用体 构造数据类型 , 也叫联合体 用途:使几个不同类型的变量共占一段内存 ( 相互覆盖 )
共用体类型定义定义形式: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;
共用体变量的定义
fch
i
fch
i
a b
共用体变量定义分配内存 ,长度 =最长成员所占字节数共用体变量任何时刻只有一个成员存在
共用体变量引用引用方式:
例 a.i=1; a.ch=‘a’; a.f=1.5; printf(“%d”,a.i); ( 编译通过,运行结果不对 )
引用规则不能引用共用体变量,只能引用其成员
共用体指针名 -> 成员名共用体变量名 . 成员名 (* 共用体指针名 ). 成员名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; ()
不能在定义共用体变量时初始化例 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低字节高字节
0100000101100001
ch[0]
ch[1]
运行结果:i=60501ch0=101,ch1=141ch0=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]);}
Ch14-7.c
结构体与共用体区别 : 存储方式不同
struct node{ char ch[2]; int k;}a;
union node{ char ch[2]; int k;}b;
achk
bch k
变量的各成员同时存在
任一时刻只有一个成员存在
联系 : 两者可相互嵌套
§ 14.9 用 typedef 定义类型功能:用自定义名字为已有数据类型命名类型定义简单形式: typedef type name;
例 typedef int INTEGER;类型定义语句关键字已有数据类型名用户定义的类型名例 typedef float REAL;
类型定义后 ,与已有类型一样使用
例 INTEGER a,b,c; REAL f1,f2;
int a,b,c; float f1,f2;
说明 :1.typedef 没有创造新数据类型2.typedef 是定义类型 ,不能定义变量3.typedef 与 define 不同 define typedef预编译时处理 编译时处理简单字符置换 为已有类型命名
typedef 定义类型步骤按定义变量方法先写出定义体 如 int i; 将变量名换成新类型名 如 int INTEGER; 最前面加 typedef 如 typedef int INTEGER; 用新类型名定义变量 如 INTEGER i,j;
例 定义数组类型 int a[100]; int ARRAY[100]; typedef int ARRAY[100]; ARRAY a,b,c;
int a[100],b[100],c[100];
例 定义指针类型 char *str; char *STRING; typedef char *STRING; STRING p,s[10];
char *p; char *s[10];
枚 举 (enum)
枚举是一个被命名的整型常数的集合 , 枚举在日常生活中很常见。 例如表示星期的 SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, 就是一个枚举。 枚举的说明与结构和联合相似 , 其形式为 :
enum 枚举名 {
标识符 [= 整型常数 ],
标识符 [= 整型常数 ],
...
标识符 [= 整型常数 ],
} 枚举变量 ;
如果枚举没有初始化 , 即省掉 "= 整型常数 " 时 , 则从第一个标识符开始 , 顺次赋给标识符 0, 1, 2, ... 。但当枚举中的某个成员赋值后 , 其后的成员按依次加 1 的规则确定其值。
例如 : 下列枚举说明后 , x1, x2, x3, x4 的值分别为 0, 1, 2, 3。 enum string{x1, x2, x3, x4}x;
当定义改变成 :
enum string
{
x1,
x2=0,
x3=50,
x4,
}x;
则 x1=0, x2=0, x3=50, x4=51
注意 :
1. 枚举中每个成员 ( 标识符 ) 结束符是 ",", 不是 ";", 最后一个成员可省略 "," 。 2. 初始化时可以赋负数 , 以后的标识符仍依次加 1 。 3. 枚举变量只能取枚举说明结构中的某个标识符常量。 例如 :
enum string
{
x1=5,
x2,
x3,
x4,
};
enum strig x=x3;
此时 , 枚举变量 x 实际上是 7 。