定义和使用结构体变量
1、定义结构体
1)结构体:用户自己建立由不同类型数据组成的组合型的数据结构。
一般形式:
struct 结构体名
{
成员列表
};
struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; };
大括号内的是结构体子项,成为结构体成员 ,成员列表也称为“域表”。
2)成员可以是另外一个结构体的变量
struct date { int month; int day; int year; } struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; struct date birthday; };
2、定义结构体类型变量
1)先声明结构体类型,再定义该类型的变量
struct student student1,student2 // student1和student2是结构体变量名
2)在声明类型的同时定义变量
一般形式:
struct 结构体名
{
成员列表
}变量名表项;
struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }student1,student2;
3)不指定类项名而直接定义结构体类型变量(即无名结构体)
一般形式:
struct
{
成员列表
}变量名列表;
补充: ① 结构体类型和结构体变量区别:只能对变量赋值,存取或运算,类型则不行。编译时,只对变量分配空间,类型不分配;
② 结构体类型的成员名可以与程序变量名同名,互不相干;
③ 结构体变量中的成员(称为“域”),可以单独使用。
3、结构体变量的初始化和引用:
例1:把一个学生的信息放在一个结构体变量中,然后输出这个学生的信息。
struct student { int num; char name[20]; char sex; char addr[30]; }student1={10101,"Li Lin",'M',"Beijing Road"}; printf("NO:%d\nname:%s\nsex:%c\naddress:%s\n",student1.num,student1.name,student1.sex,student1.addr); return 0;
1)引用结构体变量中的成员的值,引用方式:
结构体变量名.成员名
“.”是“成员运算符”在所有运算符中优先级最高.
2)如果成员本身又属于一个结构体类型,则要用若干个成员运算符,一级一级的地找到最低的一级的成员:
student1.num student1.birthday.month // 结构体变量中student1中的成员birthday中的成员month
3)结构体变量的成员像普通变量一样,可以进行各种运算(例如:赋值、自加、自减):
student2.score=student1.score; sum=student1.score+student2.score; student1.age++;
4)同类型的结构体变量可以相互赋值:
student1=student2;
5)可以应用结构变量成员的地址和结构体变量的地址:
scanf("%d",student1.num); // 输入student1.num的值
printf("%0",&student1); // 输出结构体变量student1的首地址
例子1:输入两个学生的学号、姓名和成绩,输出成绩较高的学生的学号、姓名和成绩:

#include<stdio.h> int main() { struct student { int num; char name[20]; float score; }student1,student2; scanf("%d%s%f",&student1.num,&student1.name,&student1.score); scanf("%d%s%f",&student2.num,&student2.name,&student2.score); printf("The higher score is:\n"); if(student1.score>student2.score) { printf("%d %s %6.2f\n",student1.num,student1.name,student1.score); } else if(student1.score<student2.score) { printf("%d %s %6.2f\n",student2.num,student2.name,student2.score); } else { printf("%d %s %6.2f\n",student1.num,student1.name,student1.score); printf("%d %s %6.2f\n",student2.num,student2.name,student2.score); } return 0; }
结构体数组
例子1:有3个候选人,每个选民只能投票选一人,要求编写一个统计选票的程序,先后输人被选人的名字,最后输出各人得票结果。

#include <stdio.h> #include <string.h> #define N 5 struct person { char name[20]; int count; }leader[3]={"Li",0,"Zhang",0,"Liang",0}; // 定义结构体数组并初始化 int main() { int i,j; char leader_name[20]; for(i=0;i<10;i++) { scanf("%s",leader_name); for(j=0;j<3;j++) { if(strcmp(leader_name,leader[j].name)==0) { leader[j].count++; } } } printf("\nResult:\n"); for(i=0;i<3;i++) { printf("%5s:%d\n",leader[i].name,leader[i].count); } return 0; }
1、结构体数组的定义和使用
1)定义结构体数组的一般形式:
struct 结构体名
{成员列表}数组名[数组长度]
2)先声明一个结构体类型,再用此类型定义结构体数组:
结构体类型 数组名 [数组长度];
struct person leader[3];
3)初始化形式:
struct person leader[3]={"Li",0,"Zhang",0,"Liang",0};
例子2:有N个学生的信息(包括学号、姓名、成绩),要求按照成绩的高低顺序输出各学生的信息。

#include <stdio.h> #define N 5 struct student { int num; char name[20]; float score; }; int main() { struct student stu[N]={ 101,"Zhang",99, 103,"Liang",80, 104,"Dai",77, 102,"Chen",98, 105,"Li",87}; // 定义结构体数组并初始化 struct student temp; // 临时结构体变量,用于交换 int i,j,k; char leader_name[20]; for(i=0;i<N-1;i++) // 这里用选择排序 { k=i; for(j=i+1;j<N;j++) { if(stu[j].score>stu[i].score) { k=j; } temp=stu[k];stu[k]=stu[i];stu[i]=temp; } } printf("\nResult:\n"); for(i=0;i<N;i++) { printf("%6d %8s %6.2f\n",stu[i].num,stu[i].name,stu[i].score); } printf("\n"); return 0; }
结构体指针
1、定义:
- 指向结构体数据的指针,一个结构体变量的起始地址 就是这个结构体变量的指针;
- 把一个结构体变量的起始地址存放在一个指针变量 中,那么,这个指针变量就指向该结构体变量;
- 指针变量既可以指向结构体变量,也可以用来指向结构体数组 中的 元素;
- 指针变量的基类型 必须与结构体变量的类型 相同
例子1:通过指向结构体变量的指针变量输出结构体变量中成员的信息

#include <stdio.h> #include <string.h> int main() { struct student { long num; char name[20]; char sex; float score; }; struct student stu_1; // 定义struct student类型的变量stu_1 struct student *p; // 定义指向struct student类型数据的指针变量p p=&stu_1; // p指向结构体变量stu_1 stu_1.num=10101; // 对结构体变量的num成员赋值 strcpy(stu_1.name,"Li Lin");// 对结构体变量的name成员赋值 stu_1.sex='M'; // 对结构体变量的sex成员赋值 stu_1.score=89.5; // 对结构体变量的score成员赋值 printf("No.:%ld\nname:%s\nsex:%c\nscore:%5.1lf",stu_1.num,stu_1.name,stu_1.sex,stu_1.score); // 正常输出结构体变量stu_1各成员的值 printf("\nNo.:%ld\nname:%s\nsex:%c\nscore:%5.1lf",(*p).num,(*p).name,(*p).sex,(*p).score); // 用指针输出 printf("\n"); return 0; }
第二个printf 是通过指向结构体变量的指针变量访问它的成员,输出stu_1各成员的值,使用的是( * p).num这样的形式。( * p)表示p指向的结构体变量,( * p).num是p指向的结构体变量中的成员num。注意* p两侧的括号不可省,因为成员运算符“ . ”优先于“ * ”运算符,* p.num就等价于* (p.num)了。
2、指向运算符
- C语言允许把 p->num 代替 (*p).num ,它表示p所指向的结构体变量中的num成员;
- p一> name等价于(*p).name;
- “->”称为指向运算符 。
如果p指向一个结构体变量,以下3种形式等价:
① 结构体变量.成员名
② ( *p).成员名
③ p->成员名
指向结构体变量的指针变量,也可以用来指向结构体数组元素。
例子1:有3个学生的信息,放在结构体数组中,要求输出全部学生的信息。

#include <stdio.h> struct student // 声明结构体类型 struct student { int num; char name[20]; char sex; float score; char addr[20]; }; struct student stu[4]={ {101,"Li",'M',90,"Beijing"}, {102,"Zhang",'M',89,"Nanjing"}, {103,"Chen",'F',87,"Guangdong"}, {104,"Dai",'M',95,"Hebei"}}; // 定义结构体数组并初始化 int main() { struct student *p; // 定义指向struct student结构体变量的指针 printf("No name sex score addr\n"); for(p=stu;p<stu+4;p++) // 指针指向结构体数组元素 { printf("%d%15s%15c%20f%15s\n",p->num,p->name,p->sex,p->score,p->addr); // 指向各结构体变量的成员 } return 0; }
程序分析过程:p是指向struct student结构体类型数据的指针变量。在for语句中先使p的初值为stu, 也就是数组stu第一个元素的起始地址。在第一次循环中输出stu[0]的各个成员值。然后执行p++,使p自加1。p加1意味着p所增加的值为结构体数组stu的一个元素所占的字节数(4+20+1+4+20=49)。执行p++后p的值等于stu+1,p指向stu[1],在第二次循环中输出stu[1]的各成员值。在执行p++后,p的值等于stu+2,再输出stu[2]的各成员值。直到p的值变为stu+4,已不再小于stu+3了,不再执行循环。
值得注意的点:
(1)如果p的初值为stu,即p指向stu的第一个元素,p加1后,p就指向下一个(结构体数组中的)元素。例如:
(++p)-> num //先使p自加1,然后得到p指向的元素中的num成员值(即102)
(p++)-> num //先求得p->num的值(即101),然后再使p自加1,指向stu[1]
(2)指向结构体类型数据的指针变量,只能用来指向结构体变量或者结构体数组中的元素,而不能用来指向结构体数组中元素的某一成员,例如下面做法是错误的:
p=stu[1].name; // 编译时将出现“警告”,表示地址类型不匹配
p虽然是存放地址的,但不是啥都放。如果要指向结构体数组中的元素的成员,必须要进行强制转换才可以,如:
p=(struct student *)stu[0].name;
此时,p的值是stu[0]元素name成员的起始地址,即stu[0].name的纯地址,但是已经把原来指向结构体数组的指针改为了指向一个student类型的数据,此时的p+1是指向stu[1]中的name。
总结:把指向结构体数组元素(一个元素包含多个成员)的指针和指向结构体数组中元素的成员的指针区分开来,一个是指向元素,一个是指向元素的成员。
用结构体变量和结构体变量的指针作函数参数
例子2:有 N个结构体变量stu,内含学生学号、姓名和3门课程的成绩。要求输出平均成绩最高的学生的信息(包括学号、姓名、3门课程成绩和平均成绩)。

#include <stdio.h> #define N 3 struct student { int num; char name[20]; float score[3]; float aver; }; int main() { struct student stu[N],*p=stu; // 定义结构体数组和结构体指针p,p指向stu数组的首元素stu[0] void input(struct student stu[]); // 声明函数,形参是结构体student类型的数组,即stu是stu[N]地址 struct student max(struct student stu[]); // 声明函数(带返回值,是一个结构体变量) void print (struct student stu); // 声明函数,形参是结构体student类型的结构体变量(用max中选出来的一个结构体变量) input (p); // p作为input函数的实参 print(max(p)); return 0; } void input(struct student stu[]) // 形参是struct student类型的数组,stu和p具有相同的地址 { int i; printf("请输入各学生的信息:学号、姓名、三门课程成绩:\n"); for(i=0;i<N;i++) { scanf("%d %s %f %f %f",&stu[i].num,stu[i].name,&stu[i].score[0],&stu[i].score[1],&stu[i].score[2]); stu[i].aver=(stu[i].score[0]+stu[i].score[1]+stu[i].score[2])/3.0; } // scanf输入每个学生对应的信息(对应成员的值),并计算每个学生的平均分放到各自的aver成员中 } struct student max(struct student stu[]) { int i,m=0; for(i=0;i<N;i++) { if(stu[i].aver>stu[m].aver) // 比较数组元素中各自的aver值 { m=i; } } return stu[m]; // 返回平均分最大的(元素)结构体变量 } void print(struct student stud) // 打印平均分最大的(元素)结构体变量成员的值 { printf("\n成绩最高的学生是:\n"); printf("学号:%d\n姓名:%s\n三门成绩:%5.1f,%5.1f,%5.1f\n平均成绩:%6.2f\n",stud.num,stud.name,stud.score[0],stud.score[1],stud.score[2],stud.aver); }
提高部分
1、共用体类型
- 把不同类型的变量放在同一段内存 的结构,称为 共用体类型(union)
- 共用体变量所占的内存长度等于最长的成员的长度
- 一般形式:
union 共用体名
{
成员列表
}变量列表;
union data { short int i; char ch; float f; }a,b,c;
ps:共用体只能单个引用成员,共用体可以没有名字。
2、枚举类型
如果一个变量只有几种可能的值,则可以定义为枚举类型 。所谓“枚举”是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。
声明枚举类型:enum 枚举类型名称 {枚举值名称,枚举值名称...};
定义枚举变量:enum 枚举类型 名称 枚举变量1 枚举变量2;
#include <stdio.h>
int main(void) { enum Color {red=10,green,blue}; enum Color rgb; for(rgb=red;rgb<=blue;rgb++) { printf("rgb is %d:\n",rgb); } }
#include <stdio.h>
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN } day; int main() { // 遍历枚举元素
for (day = MON; day <= SUN; day++) { printf("枚举元素:%d \n", day); } }