null第11章 结构体第11章 结构体
11.1概述
11.2定义结构体类型变量的方法 11.3结构体变量的引用
11.4结构体变量的初始化
11.5结构体数组
11.6指向结构体类型数据的指针
null11.1概述
在日常生活中,常会遇到一些需要填写的登记表,如住宿表、通讯地址、学生登记表等。在学生登记表中我们通常会登记:
姓名、学号、性别、年龄、成绩等项目;
这些数据往往具有不同的数据类型。例如,在学生登记表中,姓名应为字符数组;学号可为整型或字符串型;年龄应为整型;性别应为字符型;成绩可为整型或实型。
为将不同数据类型、但相互关联的一组数据,组合成一个有机整体使用,C语言引入一种能集中不同数据类型于一体的数据类型——结构(体)类型(struct) 11.2 定义结构体类型变量的方法11.2 定义结构体类型变量的方法C语言中的结构体类型,相当于其它高级语言中的“记录”类型
结构体类型定义形式:
struct 结构体名 /* struct是结构体类型关键字*/ {数据类型 成员名; 数据类型 成员名; …… …… 数据类型 成员名; }; /* 此行分号不能少!*/
成员类型可以是
基本型或构造型null例如:
struct student
{
int num;
char name[20];
char sex;
float score;
};
在student结构体定义中,结构体名为student,该结构体由4个成员组成。第一个成员为num,整型变量;第二个成员为name,字符数组;第三个成员为sex,字符变量;第四个成员为score,实型变量。struct student为结构体类型。
结构体是一种构造类型,它是由若干成员组成的。每一个成员可以是一个基本数据类型或者又是一个构造类型。 null再如: 定义一个反映学生基本情况的结构体类型,用以存储学生的相关信息。 /*功能:定义一个反映学生基本情况的结构体类型*/ struct date /*日期结构类型:由年、月、日三项组成*/
{int year;
int month;
int day;
};
struct std_info /*学生信息结构类型:由学号、姓名、性别和生日共4项组成*/
{char no[7];
char name[9];
char sex[3];
struct date birthday; /*成员为结构体类型,多级结构体类型*/
};
struct score /*成绩结构类型:由学号和三门成绩共4项组成*/
{char no[7];
int score1;
int score2;
int score3;
}; null11.2.1 结构体变量定义
用户自己定义的结构体类型,与系统定义的标准类型(int、char等)一样,可用来定义结构体类型的变量。结构体类型只能表示一个结构体形式,编译系统并不对它分配内存空间。在定义了结构体的变量以后,系统会为结构体变量分配内存单元。
1.定义结构变量的方法:
(1)间接定义法──先定义结构类型、再定义结构变量
struct student
{ int num;
char name[20];
char sex;
float score;
};
struct student student1, student2;
结构体类型名 结构体变量名
说明了两个变量student1和student2为stduent结构体类型。 null(2)直接定义法──在定义结构类型的同时,定义结构变量
例如,结构变量student的定义可以改为如下形式:
struct student
{
int num;
char name[20];
char sex;
float score;
}student1, student2;
2.说明
(1)结构类型与结构变量是两个不同的概念,其区别如同int类型与int型变量的区别一样。
(2)结构类型中的成员名,可以与程序中的变量同名,它们代表不同的对象,互不干扰。如变量num 和struct student 中的num不代表同一变量,有不同的存储空间。null(3)如果程序规模比较大,往往将对结构体类型的声明集中放到一个以.h为后缀的“头文件”中。哪个源文件需用到此结构体类型,则可用#include命令将该头文件包含本文件中。这样就可以定义此种结构体变量了。例如,上例存入student.h,就可以直接使用struct student 类型了。
#include "student.h"
main()
{
struct student student1, student2;
…
} 11.3 结构变量的引用11.3 结构变量的引用 1.结构变量的引用规则
对于结构变量,要通过成员运算符“.”,逐个访问其成员,且只能对成员引用,访问的格式为:
结构变量.成员 /*其中的“.”是成员运算符*/
例如:
student2. score = student1.score;
sum = student1.score + student2.score;
printf("%d",student1.birthday.year);
student1.age++;
由于“.”运算符的优先级最高,因此student1.age++是对student1.age进行加1运算。 null2.多极结构体类型变量的引用规则
如果某成员本身又是一个结构类型,则只能通过多级的分量运算,对最低一级的成员进行引用。
此时的引用格式扩展为:
结构变量.成员.子成员.….最低1级子成员
例如,引用结构变量student中的birthday成员的格式分别为:
student.birthday.year
student.birthday.month
student.birthday.day
(1)对最低一级成员,可像同类型的普通变量一样,进行相应的各种运算。
(2)既可引用结构变量成员的地址,也可引用结构变量的地址。
例如,&student.name ,&student 。null 例 显示输入的年、月、日
#include
void main()
{
struct date /*定义了结构体类型 */
{
int month;
int day;
int year;
};
struct date today; /*定义结构体变量today*/
printf("Enter today's date(年, 月, 日)\n");
scanf("%d, %d, %d", &today.year, &today.month, &today.day);
printf("Today's date is %d/%d/%d\n", today.year, today.month, today.day);
}
执行后可以显示出所输入的的年、月、日。 11.4结构体变量的初始化11.4结构体变量的初始化 和其它类型变量一样,对结构体变量可以在定义时候指定初始值#include
void main()
{ struct student
{ long int num; char name[20];
char sex;
char addr[20];
}a={1010,”Li Lin”,’M’, “123 Beijing Road”};
}11.5 结构体数组11.5 结构体数组一个结构体变量可以存放一个学生的数据,对多个学生就要使用结构体数组。结构体数组的每一个元素,都是结构类型数据。
说明结构体数组的方法和结构体变量相似, 只需说明它为数组类型即可。
例如:
struct wage
{ char name[30];
float salary;
};
struct wage persons[100];
这就说明了100个结构体变量所组成的数组。结构体数组的每一个元素都是具有相同结构体类型的下标结构体变量。在实际应用中,经常用结构体数组来表示具有相同数据结构体的一个群体。如一个班的学生档案,一个车间职工的工资表等。 null例计算学生的平均成绩和不及格的人数。
struct student
{
int num;
char name[20];
char sex;
float score;
};
struct student boy[5]={
{101, "Li ping", 'M', 45},
{102, "Zhang ping", 'M', 62.5},
{103, "He fang", 'F', 92.5},
{104, "Cheng ling", 'F', 87},
{105, "Wang ming", 'M', 58}
}; /*全局变量*/
null main()
{
int i, c=0;
float ave, s=0;
for(i=0;i<5;i++)
{
s+=boy[i].score;
if(boy[i].score<60) c+=1;
}
printf("s=%f\n", s);
ave=s/5;
printf("average=%f\ncount=%d\n", ave, c);
}
本例程序中定义了一个外部结构体数组boy,共5个元素,并作了初始化赋值。在main函数中用for语句逐个累加各元素的score 成员值存于s之中,如score的值小于60(不及格)即计数器C加1,循环完毕后计算平均成绩,并输出全班总分,平均分及不及格人数。 null对候选人得票的统计程序。设3个候选人,10人参加选举,求各候选人得票数。
#include
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++;
} /*统计相应候选人得票数,运算符.优先级高于++*/
printf(“\n”);
for(i=0;i<3;i++)
printf(“%5s:%d\n”, leader[i].name, leader[i].count); /*输出候选人姓名和得票数*/
}结构体与函数 结构体与函数 向函数传递结构体变量成员
结构体变量的成员可作为参数传递给另一函数,用法和普通变量一样。例如有类型和变量定义:
struct fred
{ char x;
int y;
float z;
char s[10];
}mike;
其中各个成员均可作为函数的参数,可使用如下调用:
func0(mike.x); /*字符型参数*/
func1(mike.y); /*整数型参数*/
func2(mike.z); /*浮点型参数*/
func3(mike.s); /*字符型数组参数*/
func4(mike.s[2]); /*字符型参数*/
null结构体变量作为函数参数 –传递结构体全部成员
结构体变量作为函数参数,对整个结构体进行传递。此时,整个结构体按传值方式传递。和普通变量一样,在函数内所引起结构体参数中某个值的变化,不影响原来的结构体变量值。
结构体作为函数参数 ,输出学生信息。
struct student
{ int num;
char name[20];
char sex;
float score; };
main()
{ struct student boy={105, “Wang ming”, ‘M’, 58}; /*结构变量初始化*/
showinfo(boy);
}
showinfo(struct student B)
{ printf("%d, %s, %c, %f\n", B.num, B.name, B.sex, B.score);
} 用结构体变量作实参时采取的是"值传递"的方式,这种方式如果结构体的规模很大时,在空间和时间上开销是很可观的。此外,改变形参结构体变量值,该值不能返回主调函数,这往往造成使用上的不便。因此,常常通过结构体指针作为参数来解决这一问题null结构体作为函数返回值 --返回结构体类型值的函数
结构体作为函数返回值。
struct student
{ int num;
char name[20];
char sex;
float score;
};
main()
{ struct student boy; /*定义结构体变量*/
struct student getinfo(); /*对被调结构体函数的说明*/
boy=getinfo(); /*对结构体函数调用,返回的结构体类型值赋boy*/
}
struct student getinfo() /*没有形参,无接受值,但有返回值*/
{ struct student B;
scanf("%d %s %c %f", &B.num, &B.name, &B.sex, &B.score);
return B;
}
用结构体变量作函数的返回值, 同样存在空间和时间上开销较大的问题。 11.6 指向结构体类型数据的指针 11.6 指向结构体类型数据的指针 11.6.1指向结构体变量的指针
一个结构变量的指针就是该变量所占据内存中的起始地址。一个指针变量用来指向一个结构体变量时,称之为结构体指针变量。结构体指针变量中的值是所指向的结构体变量的首地址。
通过结构体指针即可访问该结构体变量,这与数组指针和函数指针的情况是相同的。指针变量也可以用来指向结构体数组中的元素。
结构体指针变量说明的一般形式为:
struct 结构体名 *结构体指针变量名
例如,在前面的例题中定义了student这个结构体,如要定义一个指向student的指针变量p,可写为:
struct student *p;
定义后p所指的类型为结构体类型,当然也可在定义student结构体时同时说明p。与前面讨论的各类指针变量相同,结构体指针变量也必须要先赋值后才能使用。 null 结构体指针变量的赋值是把结构体变量的首地址赋予该指针变量,不能把结构体名赋予该指针变量。如果boy是被说明为student类型的结构体变量,则:
p=&boy;
是正确的,而:
p=boy;
是错误的。
有了结构体指针变量,就能更方便地访问结构体变量的各个成员。
其访问的一般形式为:
(*结构体指针变量).成员名
或为:
结构体指针变量->成员名
其中->称为指向运算符。 null例11.3 指向结构体变量的指针的应用。
main()
{
struct student
{ long num;
char name[20];
char sex;
float score;
};
struct student student_1={89101, "Li Lin", 'M'};
struct student *p;
p=&student_1; /*将student_1 指针赋给结构体指针变量P*/
p->score=89.5; /*对结构体指针变量所指成员score赋值 */结构体成员的赋值
student_1.num=89101
strcpy(student_1.name,"Li Lin");
(*p).sex='M'
*p表示p指向的结构体变量,*低于.需要用(*p),( )与.同级,左结合。
->指向结构体成员运算符。nullprintf("No.:%ld\nname:%s\nsex:%c\nscore:%f\n",student_1.num,
student_1.name, student_1.sex, student_1.score);
printf("No.:%ld\nname:%s\nsex:%c\nscore:%f\n", (*p).num, (*p).name,
(*p).sex, (*p).score);
printf("No.:%ld\nname:%s\nsex:%c\nscore:%f\n", p->num, p->name,
p->sex, p->score);
}
程序运行结果如下:
No.:89101
name:Li Lin
sex:M
score:89.500000
No.:89101
name:Li Lin
sex:M
score:89.500000
No.:89101
name:Li Lin
sex:M
score:89.500000
3个printf函数输出的结果是相同的。也就是说,以下三种形式等价:
① 结构体变量.成员名
② (*p).成员名
③ p->成员名 (直观、方便)
null11.6.2指向结构体数组的指针
指针变量可以指向一个结构体数组,这时结构体指针变量的值是整个结构体数组的首地址。结构体指针变量也可指向结构体数组的一个元素,这时结构体指针变量的值是该结构体数组元素的首地址。
设p为指向结构体数组的指针变量,则p+1指向1号元素,p+i则指向i号元素。这与普通数组的情况是一致的。
例11.4 用指针变量输出结构体数组。
struct student
{ int num;
char name[20];
char sex;
int age;
};
struct student student[3]={
{10101, "LiLin", 'M', 18},
{10102, "Zhang Fun", 'M', 19},
{10104, "Wang Min", 'F', 20}
}; nullmain()
{ struct student *p;
printf("No. Name sex age\n");
for(p=student;pnum, p->name ,
p->sex, p->age);
}
运行结果如下:
No. Name sex age
10101 Li Lin M 18
10102 Zhang Fun M 19
10104 Wang Min F 20
p是指向struct student结构体类型的指针变量,在for语句中先使p的初值为student,也就是数组student的起始地址。循环中使p加1。p加1意味着p指向结构体数组student的下一个元素,而不是下一个成员。 null11.6.3结构体指针变量作函数参数和返回值
前面已经介绍,用结构体变量作函数参数进行传送要将全部成员逐个传送,将会使传送的时间和空间开销很大,严重地降低了程序的效率。因此最好的办法就是使用指针变量作函数参数进行传送。这时由实参传向形参的只是地址,从而减少了时间和空间的开销。
例 输入和输出一组学生的基本信息。用结构体指针变量作函数参数编程。
struct student
{ int num;
char name[20];
char sex;
float score;
};
main()
{ struct student boy[5]; /*局部结构体数组*/
getinfos(&boy);
showinfos(&boy);
} nullvoid getinfos(struct student *B) /*输入一组学生的信息*/
{ int i;
for(i=0;i<5;i++)
{ scanf("%d %s %c %f", &B->num, &B->name, &B->sex, &B->score);
B++;
}
}
showinfos(struct student *C) /*输出一组学生的信息*/
{ int i;
for(i=0;i<5;i++)
{ printf("%d, %s, %c, %f\n", C->num, C->name, C->sex, C->score);
C++;
}
}
null 例 查询学号为102的学生的基本信息。用结构体指针变量作函数返回值编程—返回结构体指针值的函数。
struct student
{ int num;
char name[20];
char sex;
float score;
};
struct student *searchinfo(struct student *B, int num)
{
int i;
for(i=0;i<5;i++)
{
if (B->num==num)
return B;
B++;
}
}
null showinfo(struct student *C)
{
printf("%d, %s, %c, %f\n", C->num, C->name, C->sex, C->score);
}
main()
{
struct student boy[5]=
{
{101, "Li ping", 'M', 45},
{102, "Zhang ping", 'M', 62.5},
{103, "He fang", 'F', 92.5},
{104, "Cheng ling", 'F', 87},
{105, "Wang ming", 'M', 58}
};
struct student *s;
s=searchinfo(boy, 102);
showinfo(s);
}
作业作业11.3,11.4,11.5