第九章 结构
?结构
?结构数组
?结构指针
?链表
?位运算
?自定义类型
学号 姓名 性别 出生地 出生年
出生月
出生日数学 物理 程序设计






出生地
年 月 日 数学 物理 程序设计
出生日期
国家 省 市 /县
学习成绩
结构:同一个数据项的若干成分构成的一个整体。
例如:学生档案,每个学生有学号、姓名、性别、出
生地、出生年月、学业成绩等。
9.1 结构
9.1.1 结构的定义
struct student {
long int num;
char name[20];
float score;
};
定义一个结构类型,struct student
9.1.2 结构变量的定义
1、先定义结构类型,再定义变量
struct student {
long int num;
char name[20];
float score;
};
struct student stu1,stu2;
num name score
stu1 200011 Zhang 85
stu2 200012 Li 94
2、定义结构类型的同
时定义变量
struct student {
long int num;
char name[20];
float score;
}stu1,stu2;
3、不指定类型名,只定
义变量
struct {
long int num;
char name[20];
float score;
}stu1,stu2;
9.1.3 结构变量的初始化
只有全局变量或静态变量才能初始化。
static struct student stu2={200012,“Li”,94};
num name score
stu2 200012 Li 94
num name score
stu1 200011 Zhang 85
struct student {
long num;
char name[20];
float score;
} stu1={200011,"Zhang",85};
9.1.4 结构变量的使用
1、结构类型变量的整体引用
(1) 不能整体输入输出,但相同类型的变量可以互
相赋值
printf("%ld%s%f",stu1); 非法
stu2=stu1; 合法
(2) 可以引用结构体变量的地址
printf("%x",&stu1); 输出 stu1的首地址
2、结构变量中分量的引用
struct student {
long int num;
char name[20];
float score;
}stu1,stu2; (1) 结构变量,分量
stu1.num = 9901;
printf("%s",stu2.name);
num name score
stu1 200011 Zhang 85
stu2 200012 Li 94
(2) 结构变量中的分量可以依据它的类型进行各种
运算
x = stu1.score;
strcpy(stu1.name,“Wang”);
(3) 可以 引用结构变量中的分量的地址
scanf("%ld",&stu1.num);
9.2 结构数组
一个结构变量只能存放一个学生的资料。
若班上有 20个学生,需要用结构数组。
即,数组中的每个元素都是结构类型。
9.2.1 定义
struct student {
long int num;
char name[20];
float score;
}stu[20];
stu[0] 200011 Zhang 85
stu[19]
200012 Li 90
200029 Zhao 70
stu[1]
9.2.2 初始化
struct student {
long int num;
char name[20];
float score;
}stu[20]={{200011,”Zhang”,85},
{200012,”Li”,90}};
stu[0] 200011 Zhang 85
stu[19]
200012 Li 90
200029 Zhao 70
stu[1]
9.2.3 引用
struct student {
long int num;
char name[20];
float score;
}stu[20];
stu[0].num
stu[0].name
stu[0].score
stu[0] 200011 Zhang 85
stu[19]
200012 Li 90
200029 Zhao 70
stu[1]
程序举例
例 1、输入某班 30位学生的姓名及数学、英语
成绩,计算并输出每位学生的平均分。
struct student{
char name[10];
int math,eng;
float aver;
};
void main( )
{ struct student s[30];
int i;
for(i=0; i<30; i++) {
scanf("%s%d%d",s[i].name,&s[i].math,
&s[i].eng);
s[i].aver = (s[i].math+s[i].eng)/2.0
printf("%s%f",s[i].name,s[i].aver);
}
}
s[0]
s[29]
s[1]
Zhang 80 85
Li 77 90
wang 60 78
输入某班 30位学生的姓名及数学、英语成绩,
计算并输出每门课程的平均分。
void main( )
{ struct student s[30];
int i;
float aver_m=0,aver_e=0;
例 2
for(i=0; i<30; i++) {
scanf("%s%d%d",s[i].name,&s[i].math,
&s[i].eng);
aver_m += s[i].math;
aver_e += s[i].eng;
}
printf("%f%f",aver_m/30,aver_e/30);
}
输入 30位学生的姓名及数学、英语成绩,输出
平均分最高的学生的姓名及其数学和英语成
绩。
struct student{
char name[10];
int math,eng;
float aver;
};
例 3
void main( )
{ struct student s[30];
int i,sub;
for(i=0; i<30; i++) {
scanf("%s%d%d",s[i].name,&s[i].math,
&s[i].eng);
s[i].aver = (s[i].math+s[i].eng)/2.0
}
sub=0;
for( i=1; i<30; i++)
if(s[i].aver > s[sub].aver ) sub = k;
printf("%s%d%d\n",s[sub].name,s[sub].math,
s[sub].eng);
}
9.3 结构指针
9.3.1 定义
struct student {
long int num;
char name[20];
float score;
};
struct student stu1,*ptr;
ptr = &stu1;
num name score
stu1
200011 Zhang 85ptr
9.3.2 结构指针的使用
struct student stu1,*ptr = &stu1;
stu1.num=200011; stu1.score=85;
strcpy(stu1.name,”Zhang”);
通过指针 ptr 访问结构分量
(1) *ptr
(*ptr).num = 200011; (*ptr).score = 85;
strcpy((*ptr).name,”Zhang”);
num name score
stu1
200011 Zhang 85ptr
(2) ->
(*ptr).num = 200011;
ptr->num = 200011; ptr->score = 85;
strcpy(ptr->name,”Zhang”);
当 ptr = &stu1时
stu1.num
(*ptr).num
ptr->num 三者 等价
num name score
stu1
200011 Zhang 85ptr
ptr->num ++ 等价于 (ptr->num) ++
++ ptr->num 等价于 ++ (ptr->num)
(++ ptr)->num
num name score
stu1
200011 Zhang 85ptr
9.4 链表 9.4.1结构的嵌套定义
struct day {
int y;
int m;
int d;
}
年 月 日 成绩
出生日期姓名学号
struct student {
long int num;
char name[20];
struct day birthday;
float score;
}
y m d score
birthdaynamenum
struct day {
int y;
int m;
int d;
};
struct student {
long int num;
char name[20];
struct day birthday;
float score;
}stu1,stu2;
y m d score
birthdaynamenum
或:
struct student {
long int num;
char name[20];
struct {
int y,m,d;
} birthday;
float score;
}stu1,stu2;
struct student {
long int num;
char name[20];
struct {
int y,m,d;
} birthday;
float score;
}stu1={9901,“Zhao”,{1980,10,30},80},stu2;
stu2.birthday.y=1979;
stu2.birthday.y=1;
stu2.birthday.y=20;
y m d score
birthdaynamenum
9.4.2 单向链表
struct student {
long int num;
float score;
struct student *next;
}
结构的递归定义
head 9901 80 9902 90 9903 75 NULL
1、动态内存分配函数
(1) void *malloc(unsigned size)
功能:在内存的动态存贮区中分配一块长度为 size
的连续空间。
返回值:指针,存放被分配内存的起始地址。若
未申请到空间,则返回 NULL( 0 )。
void *:指向任何类型的数据,在使用时,要进行
强制类型转换。
例如,(int *) malloc(sizeof(int))
(struct student *) malloc(sizeof(struct student))
(2) void free(void *ptr)
功能:释放由 malloc()申请的动态内存空间, ptr存
放 该空间的首地址 。
返回值:无 。
p=(struct student *) malloc(sizeof(struct student));
……
free(p);
2、建立链表
编写一个函数, 要求用单向链表建立学生档案, 从
键盘输入数据, 如果学号为 0,输入结束, 并返回
链表的头指针 。
struct student {
long int num;
float score;
struct student *next;
};
struct student *head,*tail,*p;
head=tail=NULL;
struct student *head,*tail,*p;
head=tail=NULL;
size=sizeof(struct student);
p = (struct student *) malloc(size);
p
num score nexthead
tail
p
tail
head=tail=NULL;
input num,score
while num!=0
p= (struct student *) malloc(sizeof(size))
p->num=num,p->score=score,p->next=NULL
y head==NULL n
head=p tail->next=p
tail=p
input num,score
# include "stdio.h"
struct student {
int num;
float score;
struct student *next;
};
struct student *creat( );
main( )
{
struct student *head;
head = creat( );
}
struct student *creat()
{ struct student *head,*tail,*p; float score;
int num,size = sizeof(struct student);
head = tail = NULL;
scanf("%d %f",&num,&score);
while (num){
p = (struct student *)malloc(size);
p->num = num; p->score = score;
p->next = NULL;
if(head == NULL) head = p;
else tail->next = p;
tail = p;
scanf("%d %f",&num,&score);
}
return head; }
3、遍历链表
ptr->num
ptr->score
head 9901 80 9902 90 9903 75 NULL
ptr ptr
for(ptr=head; ptr!=NULL; ptr=ptr->next)
printf(“%ld,%f”,ptr->num,ptr->score);
ptr=ptr->next
# include "stdio.h"
struct student {
int num;
float score;
struct student *next;
};
struct student *creat( );
void print(struct student *head)
main( )
{ struct student *head;
head = creat();
print(head);
}
void print(struct student *head)
{ struct student *ptr;
if(head == NULL){
printf("\n No list\n");
return;
}
printf("\n list\n");
for (ptr = head; ptr; ptr = ptr->next)
printf(" %d %f\n",ptr->num,ptr->score);
}
4、对链表的删除操作
ptr2=ptr1->next
ptr1->next=ptr2->next
head
ptr1 ptr2
head
ptr1
free(ptr2)
ptr2=ptr1->next
ptr2
4、对链表的插入操作
s->next = ptr->next
ptr->next = s
先连后断
head
ptr
s
9.5 位运算
9.5.1 位运算符
1、位逻辑运算符
~ 按位取反 (与 !同级 ) 单目右结合
& 按位与
^ 按位异或 相同取 0,不同取 1
| 按位或
1、位逻辑运算符
~ 按位取反
& 按位与
^ 按位异或 相同取 0,不同取 1
| 按位或
x=0 00000000 00000000
y=3 00000000 00000011
x&y 00000000 00000000
x|y 00000000 00000011
x^y 00000000 00000011
1010 ^ 0101 =1111
注意区分:
&和 |
&&和 ||
x && y得 0
x || y得 1
2、位移位运算符
<< 对操作数左移给出的位数
>> 对操作数右移给出的位数
x<<3 将 x向 左移 3位,空出的位用零填补
00111010 << 3
11010000
x>>3 将 x向右移 3位
00111010 >> 3
00000111
3、复合位赋值运算符
&=
|=
^=
>>=
<<=
例,a&=b 相当于 a=a&b
a<<=2 相当于 a=a<<2
9.6 自定义类型
用 typedef 定义新的类型名代替已有的类型
旧 新
例 1,typedef int INTEGER;
int i,j; <====> INTEGER i,j;
例 2,typedef int* POINT;
int* p1; <====> POINT p1;
定义方法
(1) 定义变量 int i
(2)变量名-, 新类型名 int INTEGER
(3)加上 typedef typedef int INTEGER
(4) 用新类型名定义变量 INTEGER i;
例 int num[10]
int NUM[10]
typedef int NUM[10]
NUM a <===> int a[10]