实验8结构体与共用体 8.1结构体 【实验目的】 1.掌握结构体变量的定义和引用: 2.掌握结构体的嵌套方法: 3. 掌握结构体变量作为函数参数时的使用方法。 【相关知识点】 1.定义结构体类型的一般格式: struct结构体名 { 成员表列 }; 示例:定义一个学生(student)结构体类型,该结构体由学号、姓名、性别、年龄、成 绩和地址等成员构成。 struct student int num; 体学号制 char name[20;/体姓名/ char sex; /体性别制 int age, 体年龄 float score: *成绩*/ char addr[30;/体地址*/ }; 该示例定义的结构体类型为struct student,.其中包含6个成员,每个成员都有自己的数据 类型。 -137
实验8 结构体与共用体 8.1 结构体 【实验目的】 1. 掌握结构体变量的定义和引用; 2. 掌握结构体的嵌套方法; 3. 掌握结构体变量作为函数参数时的使用方法。 【相关知识点】 1. 定义结构体类型的一般格式: struct 结构体名 { 成员表列 }; 示例:定义一个学生(student)结构体类型,该结构体由学号、姓名、性别、年龄、成 绩和地址等成员构成。 struct student { int num; /* 学号 */ char name[20]; /* 姓名 */ char sex; /* 性别 */ int age; /* 年龄 */ float score; /* 成绩 */ char addr[30]; /* 地址 */ } ; 该示例定义的结构体类型为 struct student,其中包含 6 个成员,每个成员都有自己的数据 类型。 - 137 -
2.定义结构体变量的三种方法 a)先定义结构体类型再定义结构体变量名 struct结构体名变量名表列; 示例: struct student student1.student2: 本例定义了studentl和student2为struct student类型的变量,即它们具有struct student类 型的结构。 注意:将一个变量定义为标准类型(基本数据类型)与定义为结构体类型不同之处在于 后者不仅要求指定变量为结构体类型,而且要求指定为某一特定的结构体类型,因为可以定 义出很多种具体的结构体类型。 b)在定义结构体类型的同时定义结构体变量 struct结构体名 成员表列: }变量名表列; 示例: struct student int num; 体学号制 char name[20;/*姓名*/ char sex; /*性别*/ int age; 体年龄* float score; 体成绩*/ char addr[30l;/体地址*/ student1,student2; 它的作用与第一种方法相同,即定义了两个struct student类型的变量studentl,.student2。 c)直接定义结构体类型变量 struct -138-
2. 定义结构体变量的三种方法 a) 先定义结构体类型再定义结构体变量名 struct 结构体名 变量名表列; 示例: struct student student1,student2; 本例定义了 student1 和 student2 为 struct student 类型的变量,即它们具有 struct student 类 型的结构。 注意:将一个变量定义为标准类型(基本数据类型)与定义为结构体类型不同之处在于 后者不仅要求指定变量为结构体类型,而且要求指定为某一特定的结构体类型,因为可以定 义出很多种具体的结构体类型。 b) 在定义结构体类型的同时定义结构体变量 struct 结构体名 { 成员表列; }变量名表列; 示例: struct student { int num; /* 学号 */ char name[20]; /* 姓名 */ char sex; /* 性别 */ int age; /* 年龄 */ float score; /* 成绩 */ char addr[30]; /* 地址*/ } student1,student2; 它的作用与第一种方法相同,即定义了两个 struct student 类型的变量 student1,student2。 c) 直接定义结构体类型变量 struct { - 138 -
成员表列: }变量名表列; 示例: struct int num; 体学号*/ char name[20];/体姓名*/ char sex; 体性别/ int age, *年龄*/ float score; *成绩 char addr[30l;/体地址*/ )studentl,student2; 直接定义结构体变量时,由于省略了结构名,因此定义语句后面无法再定义这个类型的 其它结构体变量,除非把定义过程再写一遍。一般情况下,还是建议采用前面两种结构变量 的定义形式。 注意: (1)在定义了结构体变量后,系统会为之分配内存单元。例如在VC+6.0系统中,结构体 变量student1和student2在内存中各占63个字节(4+20+1+4+4+30=63)。 (2)对结构体中的成员,可以单独使用,它的作用与地位相当于普通变量。 (3)成员也可以是一个结构体变量。 (4)成员名可以与程序中其他的变量名相同,但二者不代表同一对象。 3.结构体变量的引用 引用结构体变量中成员的方式为: 结构体变量名成员名 示例1:使用赋值语句给结构体成员赋值。 student1.num=10010: studentl.num表示studentl变量中的num成员。可以对变量的成员赋值,“.”是成员运 算符,它在所有的运算符中优先级最高,因此可以把student1.num作为一个整体来看待。 示例2:使用输入函数给结构体成员赋值。 -139-
成员表列; }变量名表列; 示例: struct { int num; /* 学号 */ char name[20]; /* 姓名 */ char sex; /* 性别 */ int age; /* 年龄 */ float score; /* 成绩 */ char addr[30]; /* 地址 */ } student1,student2; 直接定义结构体变量时,由于省略了结构名,因此定义语句后面无法再定义这个类型的 其它结构体变量,除非把定义过程再写一遍。一般情况下,还是建议采用前面两种结构变量 的定义形式。 注意: (1) 在定义了结构体变量后,系统会为之分配内存单元。例如在 VC++6.0 系统中,结构体 变量 student1 和 student2 在内存中各占 63 个字节(4+20+1+4+4+30=63)。 (2) 对结构体中的成员,可以单独使用,它的作用与地位相当于普通变量。 (3) 成员也可以是一个结构体变量。 (4) 成员名可以与程序中其他的变量名相同,但二者不代表同一对象。 3. 结构体变量的引用 引用结构体变量中成员的方式为: 结构体变量名.成员名 示例 1:使用赋值语句给结构体成员赋值。 student1.num=10010; student1.num 表示 student1 变量中的 num 成员。可以对变量的成员赋值,“.”是成员运 算符,它在所有的运算符中优先级最高,因此可以把 student1.num 作为一个整体来看待。 示例2:使用输入函数给结构体成员赋值。 - 139 -
scanf("%d",&student1.num); 该示例使用输入函数输入student1.num的值。 示例3:对结构体变量初始化。 struct student long int num; char name[20]; char sex; char addr[20]; )a={10101,"LiLin",'M,"123 Beijing Road"); 【实验任务】 一、程序改错 该部分实验主要训练学生阅读简单程序的能力,并在理解程序的基础上,改正程序中出 现的错误。以下是结构体部份初学者容易犯的错误: 1)结构体类型与结构体变量混淆: 2)定义结构体变量的方法错误: 3)结构体变量的成员赋值的方法错误: 下面通过读程序改错练习,掌握结构体类型和结构体变量的正确使用方法。 1.打开c:lc-programming\8\pg8I01.cpp,该程序要求从键盘输入某个学生的学号、姓名、 性别和年龄,然后将结果输出。但程序中存在若干个问题,请查找程序中的错误并修改,使 程序能正确运行。修改后的程序以pg8101_ok.cpp保存。该源程序内容如下: #include struct stu 体学生信息制 int no; 体学号*制 char name[10]; /*姓名*/ char sex[3]; 体性别*/ int age, *年龄*/ -140-
scanf("%d",&student1.num); 该示例使用输入函数输入 student1.num 的值。 示例 3:对结构体变量初始化。 struct student { long int num; char name[20]; char sex; char addr[20]; }a={10101,"LiLin",'M',"123 Beijing Road"}; 【实验任务】 一、程序改错 该部分实验主要训练学生阅读简单程序的能力,并在理解程序的基础上,改正程序中出 现的错误。以下是结构体部份初学者容易犯的错误: 1) 结构体类型与结构体变量混淆; 2) 定义结构体变量的方法错误; 3) 结构体变量的成员赋值的方法错误; 下面通过读程序改错练习,掌握结构体类型和结构体变量的正确使用方法。 1.打开 c:\c-programming\8\pg8101.cpp,该程序要求从键盘输入某个学生的学号、姓名、 性别和年龄,然后将结果输出。但程序中存在若干个问题,请查找程序中的错误并修改,使 程序能正确运行。修改后的程序以 pg8101_ok.cpp 保存。该源程序内容如下: #include struct stu /* 学生信息 */ { int no; /* 学号 */ char name[10]; /* 姓名 */ char sex[3]; /* 性别 */ int age; /* 年龄 */ - 140 -
} void main (void { printf("请输入学号,姓名,性别,年龄")方 scanf("%d%s%c%d",stu.no,stu.name,stu.sex,stu.age); printf("学号:%d,姓名:%s,性别:%c,年龄:%dn",stu.no,stu.name,stu.sex,stu.age, 了提示:如何发现问题? 编译该程序,系统报告很多条语法错误。遇到这种情况时,请不要惊慌失措,可以按以 下步骤来进行检查: (1)结构体类型定义是否有错误?经检查,会发现定义结构体变量时,在结尾处缺少了 一个分号“,”。不少同学在定义结构体时,会忘记在语句后面加上分号。 (2)重新编译,仍然发现有错,系统提示:“'stu:illegal use of this type as an expression”。 这是因为上述程序中,只定义了结构体类型,没有定义结构体变量。而该程序错误地将结构 体类型名当作结构体变量名来使用。 (3)在使用scaf给函数结构体变量成员赋值时,除结构体成员是字符数组时不需要加 地址符号“&”之外,其它类型的成员均要加地址符号“&”。例如:假设结构体变量名是s, 在给结构体成员no赋值时,正确的格式应当是scanf"%d",&s.no),而在给成员name赋值时, 由于name是字符数组,可以不需要使用“&”,例如: scanf("%s",s.name); 改正程序后的运行结果示例如图8.1.1所示。 "C:\c-programming\Debug\pg8101_ok.exe" 回☒ 请输入学号、姓名、性别、年龄 101张三男,28 学号:11,姓名:张三。性别:男.年龄:28 ess any key to continue 图8.1.1Pg8101_ok.cpp的运行结果 2.打开c:lc-programming\8pg8I02.cpp,该程序要求在结构体变量初始化时给各个成员赋 值,然后将结果输出。但程序中存在若干个问题,请修改其中的错误,使程序能正确运行。 修改后的程序以pg8102_ok.cpp保存。该源程序内容如下: #include -141-
} void main (void ) { printf("请输入学号,姓名,性别,年龄"); scanf("%d%s%c%d",stu.no,stu.name,stu.sex,stu.age); printf("学号:%d, 姓名:%s, 性别:%c, 年龄:%d\n",stu.no,stu.name,stu.sex,stu.age); } 提示:如何发现问题? 编译该程序,系统报告很多条语法错误。遇到这种情况时,请不要惊慌失措,可以按以 下步骤来进行检查: (1)结构体类型定义是否有错误?经检查,会发现定义结构体变量时,在结尾处缺少了 一个分号“;”。不少同学在定义结构体时,会忘记在语句后面加上分号。 (2)重新编译,仍然发现有错,系统提示:“'stu': illegal use of this type as an expression”。 这是因为上述程序中,只定义了结构体类型,没有定义结构体变量。而该程序错误地将结构 体类型名当作结构体变量名来使用。 (3)在使用 scanf 给函数结构体变量成员赋值时,除结构体成员是字符数组时不需要加 地址符号“&”之外,其它类型的成员均要加地址符号“&”。例如:假设结构体变量名是 s, 在给结构体成员 no 赋值时,正确的格式应当是 scanf("%d",&s.no),而在给成员 name 赋值时, 由于 name 是字符数组,可以不需要使用“&”,例如: scanf("%s",s.name); 改正程序后的运行结果示例如图 8.1.1 所示。 图 8.1.1 pg8101_ok.cpp 的运行结果 2.打开 c:\c-programming\8\pg8102.cpp,该程序要求在结构体变量初始化时给各个成员赋 值,然后将结果输出。但程序中存在若干个问题,请修改其中的错误,使程序能正确运行。 修改后的程序以 pg8102_ok.cpp 保存。该源程序内容如下: #include - 141 -
struct student 体学生信息* int no=1001: *学号/ char name[10]="Zhang"; /体姓名*/ char sex[2]="男"; /体性别*/ int age=20; /体年龄*/ stu; void main(void printf("学号:%d,姓名:%s,性别:%s,年龄:%dn",stu.no,stu.name,stu.sex,stu.age; } 了提示:如何发现问题? 在定义结构体类型时,不能对结构体成员赋初值。在初始化结构体变量成员时,套用基 本类型变量的初始化方法,是常犯的错误。通过这个实例,可以掌握结构体变量的初始化方 法。 可以参考下列方式给结构体变量赋初值: struct student 体学生信息*/ { int no; /体学号*/ char name[10]; 体姓名*/ char sex[2]; 体性别*/ int age, /体年龄*/ }stu={1001,"Zhang'","男",20 改正程序后的运行结果示例如图8.1.2所示。 "C:\c-programming\Debug\pg8102_ok.exe" 回☒ 学号:1g1,姓名:Zhang,性别:男,年龄:2g Press any key to continue 图8.1.2pg8102_ok.cpp运行结果 -142
struct student /* 学生信息 */ { int no=1001; /* 学号 */ char name[10]= "Zhang"; /* 姓名 */ char sex[2]= "男"; /* 性别 */ int age=20; /* 年龄 */ }stu; void main (void ) { printf("学号:%d, 姓名:%s, 性别:%s,年龄:%d\n", stu.no,stu.name,stu.sex,stu.age); } 提示:如何发现问题? 在定义结构体类型时,不能对结构体成员赋初值。在初始化结构体变量成员时,套用基 本类型变量的初始化方法,是常犯的错误。通过这个实例,可以掌握结构体变量的初始化方 法。 可以参考下列方式给结构体变量赋初值: struct student /* 学生信息 */ { int no; /* 学号 */ char name[10]; /* 姓名 */ char sex[2]; /* 性别 */ int age; /* 年龄 */ }stu={1001, "Zhang", "男", 20}; 改正程序后的运行结果示例如图 8.1.2 所示。 图 8.1.2 pg8102_ok.cpp 运行结果 - 142 -
3.打开c:lc-programming8pg8I03.cpp,要求从键盘输入某个学生的学号、姓名、出生年 月日,然后将结果输出。该程序使用结构体嵌套,请检查该程序的错误并修改,使程序能正 确运行。修改后的程序以pg8103ok.cpp保存。该源程序内容如下: #include struct student /体学生信息/ { int no; 体学号*/ char name[10]; 体姓名*/ struct date birthday; /*日期*/ : struct date /体日期信息 { int month: /体月*制 int day; *日*1 int year, /*年*/ void main (void struct student s; printf("请输入学号、姓名、出生日期(年月日)n")方 scanf"%d%s%d%d%d" &s.no,s.name,&birthday.year,&birthday.month,&birthday.day); printf("学号:%d,姓名:%s,出生日期:%5d%4d%4d小n", s.no,s.name,birthday.year,birthday.month,birthday.day); 了提示:如何发现问题? 结构体可以嵌套使用,但要注意:在定义嵌套的结构类型时,必须先定义成员的结构类 型,再定义主结构类型。即:如果一个结构类型被引用于另一个结构类型中时,就必须在引 用的结构类型前事先定义,否则无法实现嵌套。这与在函数调用时必须事先声明或定义是同 -143-
3.打开 c:\c-programming\8\pg8103.cpp,要求从键盘输入某个学生的学号、姓名、出生年 月日,然后将结果输出。该程序使用结构体嵌套,请检查该程序的错误并修改,使程序能正 确运行。修改后的程序以 pg8103_ok.cpp 保存。该源程序内容如下: #include struct student /* 学生信息 */ { int no; /* 学号 */ char name[10]; /* 姓名 */ struct date birthday; /* 日期 */ }; struct date /* 日期信息 { int month; /* 月 */ int day; /* 日 */ int year; /* 年 */ }; void main (void ) { struct student s; printf("请输入学号、姓名、出生日期(年月日)\n"); scanf("%d%s%d%d%d", &s.no,s.name,&birthday.year, &birthday.month,&birthday.day); printf("学号: %d, 姓名:%s, 出生日期:%5d%4d%4d\n", s.no,s.name,birthday.year,birthday.month,birthday.day); } 提示:如何发现问题? 结构体可以嵌套使用,但要注意:在定义嵌套的结构类型时,必须先定义成员的结构类 型,再定义主结构类型。即:如果一个结构类型被引用于另一个结构类型中时,就必须在引 用的结构类型前事先定义,否则无法实现嵌套。这与在函数调用时必须事先声明或定义是同 - 143 -
样的道理。另外,当对嵌套结构的成员引用时,要求使用若干个成员运算符,逐级地找到最 低一级的成员。只能对最低级的成员进行赋值、存取或运算。 改正程序后的运行结果示例如图81.3所示。 "C:\c-programming\Debug\pg8103_ok.exe" 回 请输入学号、姓名、出生日期(年月日) 1001 zhang 1991 10 1 学号:101,姓名:zhang.,出生日期:19911B1 Press any key to continue 图8.1.3pg8103_ok.cpp运行结果 二、程序扩展 1.打开c:lc-programming\8\pg8201.cpp,该程序完成手机通讯录联系人的输入和输出功能。 该源程序内容如下: #include struct friends list 体手机通讯录结构定义*/ { char name[10]; /*姓名*/ int age; /体年龄*/ char telephone[l3];/体联系电话*/ 5 void main(void) struct friends list s; printf"请输入姓名、年龄和联系电话:ln")方 scanf("%s%d%s",s.name,&s.age,s.telephone); printf("姓名:%s,年龄:%4d,联系电话:%sln",s.name,s.age,s.telephone; } 要求:修改上面的程序,在主函数中输入数据,在输出函数output()中将结果输出。修改 结果源程序以pg820la.cpp保存。 训练要点:掌握结构体变量作为函数参数的使用方法。 -144-
样的道理。另外,当对嵌套结构的成员引用时,要求使用若干个成员运算符,逐级地找到最 低一级的成员。只能对最低级的成员进行赋值、存取或运算。 改正程序后的运行结果示例如图 8.1.3 所示。 图 8.1.3 pg8103_ok.cpp 运行结果 二、程序扩展 1.打开 c:\c-programming\8\pg8201.cpp,该程序完成手机通讯录联系人的输入和输出功能。 该源程序内容如下: #include struct friends_list /* 手机通讯录结构定义 */ { char name[10]; /* 姓名 */ int age; /* 年龄 */ char telephone[13]; /* 联系电话 */ }; void main(void) { struct friends_list s; printf("请输入姓名、年龄和联系电话:\n"); scanf("%s%d%s",s.name, &s.age, s.telephone); printf("姓名:%s, 年龄:%4d, 联系电话:%s\n", s.name,s.age,s.telephone); } 要求:修改上面的程序,在主函数中输入数据,在输出函数 output()中将结果输出。修改 结果源程序以 pg8201a.cpp 保存。 训练要点:掌握结构体变量作为函数参数的使用方法。 - 144 -
修改后程序的运行结果如图8.1.4所示。 e"C:\c-programming\Debug\pg8201a.exe" 回X 请输入姓名、年龄和联系电话: 三200757-83325897 输出结果:姓名:张三,年龄:20,联系电话:57-83325897 Press any key to continue 4 图8.1.4pg8201a.cpp的运行结果 2.打开c:lc-programming\8pg8202.cpp,该程序完成手机通讯录联系人的输入和输出功能。 该源程序内容如下: #include struct friends list 体手机通讯录结构定义*/ { char name10; /*姓名*/ int age, /*年龄* char telephone[13]; 体联系电话*/ } struct friends list input() /体输入姓名、年龄和联系电话/ … void output(struct friends list t) /体输出姓名、年龄和联系电话*/ } void main(void) { struct friends list x; x=input();/体调用输入函数,结果赋值给x*/ -145-
修改后程序的运行结果如图 8.1.4 所示。 图 8.1.4 pg8201a.cpp 的运行结果 2.打开 c:\c-programming\8\pg8202.cpp,该程序完成手机通讯录联系人的输入和输出功能。 该源程序内容如下: #include struct friends_list /* 手机通讯录结构定义 */ { char name[10]; /* 姓名 */ int age; /* 年龄 */ char telephone[13]; /* 联系电话 */ }; struct friends_list input( ) { /* 输入姓名、年龄和联系电话 */ …… } void output(struct friends_list t) { /* 输出姓名、年龄和联系电话 */ …… } void main(void) { struct friends_list x; x=input(); /* 调用输入函数,结果赋值给 x */ - 145 -
output((x),/体调用输出函数*/ } 要求:修改上面的程序,在输入函数input()中完成联系人的数据输入功能,在输出函数中 完成联系人的输出功能,在主函数中调用输入函数完成输入数据,在输出函数output(中将结 果输出。注意:不得修改主函数中的任何语句。修改结果源程序以pg8202acpp保存。 训练要点:掌握结构体变量在函数调用过程中,形参和实参的使用方法,掌握结构体变 量在函数之间进行数据传递的原理。结构变量不仅可以作为函数参数,也可以作为函数的返 回值,与普通变量作为函数参数一样。 修改后程序的运行结果如图8.1.5所示。 "C:\c-programming\Debug\pg8202a.exe" 回☒ 请输入姓名、年龄和联系电话: 5=,2082980757 裔出结果:姓名:张三,年龄:20,联系电话:82980757 Press any key to continue 图8.1.5pg8202a.cpp的运行结果 三、程序编写 1.编写程序,完成两个复数相加运算。编写的源程序以pg8301.cpp保存。 提示:定义一个能够表示复数的结构类型,一个复数包括实数和虚数两个部分。 训练要点:用结构体类型解决数学中的复数运算问题。 程序运行结果参考示例如图81.6所示。 "C:\e-programming\Debug\pg8301.exe 回☒ x的实部值和虚部值:1.232.45 y的实部值和虚部值:3.142.?1 相加结果:2=4.370000+5.1606801 Press any key to continue 图8.1.6pg8301.cpp的运行结果 2.编写程序,输入一个日期,计算并输出该日是该年中的第几天。要求编写函数计算某 日是该年中的第几天,用结构指针作为函数参数,注意闰年问题。编写的源程序以pg8302.cp即 保存。 提示:定义一个日期结构体类型,调用一个自定义函数计算天数并返回计算结果。 -146-
output(x); /* 调用输出函数 */ } 要求:修改上面的程序,在输入函数 input()中完成联系人的数据输入功能,在输出函数中 完成联系人的输出功能,在主函数中调用输入函数完成输入数据,在输出函数 output()中将结 果输出。注意:不得修改主函数中的任何语句。修改结果源程序以 pg8202a.cpp 保存。 训练要点:掌握结构体变量在函数调用过程中,形参和实参的使用方法,掌握结构体变 量在函数之间进行数据传递的原理。结构变量不仅可以作为函数参数,也可以作为函数的返 回值,与普通变量作为函数参数一样。 修改后程序的运行结果如图 8.1.5 所示。 图 8.1.5 pg8202a.cpp 的运行结果 三、程序编写 1.编写程序,完成两个复数相加运算。编写的源程序以 pg8301.cpp 保存。 提示:定义一个能够表示复数的结构类型,一个复数包括实数和虚数两个部分。 训练要点:用结构体类型解决数学中的复数运算问题。 程序运行结果参考示例如图 8.1.6 所示。 图 8.1.6 pg8301.cpp 的运行结果 2.编写程序,输入一个日期,计算并输出该日是该年中的第几天。要求编写函数计算某 日是该年中的第几天,用结构指针作为函数参数,注意闰年问题。编写的源程序以 pg8302.cpp 保存。 提示:定义一个日期结构体类型,调用一个自定义函数计算天数并返回计算结果。 - 146 -