第35题  结构体的接收、修改与返回3

本题程序中,学生结构体stu包含3个成员:学号no、姓名name和成绩score,函数fun通过结构体指针形参s接收一个结构体,对其部分成员进行修改。形参s先指向结构体:学号为10002、姓名为Johnson、成绩为90、84、78,再将其学号和姓名分别修改成:学号为10006、姓名为Tom、但成绩不变。­

请在程序的下划线处填入正确内容并把下划线删除,使程序得出正确结果。注意:源程序存放在考生文件夹下的BLANK1.C中。 不许增行或删行,也不许更改程序结构。

BLANK1.C:

BLANK35-01

参考答案:

BLANK35-02

运行结果:

BLANK35-03

程序解析:

编译预处理指令#include <stdio.h>让预处理器用头文件stdio.h的内容替换#include <stdio.h>这一行,这叫做文件包含,用来包含标准函数库的有关信息,以支持printf、scanf等一族库函数的调用。程序要调用某个库函数,就必须包含与之对应的头文件。文件包含指令通常位于源程序开头处,而且要单独占一行、结尾无标点。#include <string.h>支持strcpy等另一族库函数的调用。

结构体类型定义

struct stu {
­      int no;
­      char name[10];
­      float score[3];
};

定义结构体类型stu,包含3个成员:学号no、长度为10的姓名字符数组name和长度为3的成绩浮点数组score。

程序从函数main开始执行。声明:

struct stu a = {10002, ″Johnson″, 90, 84, 78};
int i;

定义a为struct stu类型的结构体变量,分配存储,并初始化,学号no为10002,姓名name为 ″Johnson″,3门课的成绩:score[0]为90、score[1]为84、score[2]为78。定义变量i,分配存储,不作初始化,用于循环控制与索引。凡未经初始化的变量,其初值无意义,仅反映新分配内存的当前随机性物理状态。至此,当前存储状态如下图所示,变量的无意义垃圾值以空白表示。注意:成员数组名name和score本质上是指向各自首元素的常量指针,常量指针只供引用但不能被赋值,其存储空间是在有关表达式计值过程中临时自动分配的,并不是结构体存储块的组成部分。由于机器内存是一维连续字节序列的本性,3个成员顺次占据一段内存,其存储结构如下图。由于存储对齐的客观要求,成员之间可能会存在若干空洞字节。

BLANK35-04

首先,执行下面的5条语句:

printf(″原结构体为:\n″);
printf(″学号: %d\n姓名: %s\n″, a.no, a.name);
printf(″成绩:″);
for (i = 0; i < 3; ++i)
­       printf(″%5.1f″, a.score[i]);
printf(″\n″);

在标准输出设备(通常是显示器)上,给出提示,并将原始结构体的内容输出。接着,执行函数调用语句fun(&a);以结构体变量a的地址为实参调用函数fun,于是,main的执行被挂起(暂停),函数fun开始执行。首先,为形参变量s分配存储,完成参数传递:将main中的结构体a的地址值&a(即指向a的指针)传值(拷贝)于fun的形参s,即让指针s指向main中的结构体a,以便通过fun中的指针s来访问main中的结构体a。为了突出s是指向含有多个成员的结构体整体,图中用红色边框标识结构体是一个集成变量。形参s也是fun的局部变量。至此,当前存储状态如下图所示。函数fun和main各有不同的存储空间、各有自己的作用域。fun的局部变量只能在fun中访问。

BLANK35-05

在函数fun中,执行下面2条语句,完成对结构体∗s的修改。

s−>no = 10006;
strcpy(s−>name, ″Tom″);

赋值语句s−>no = 10006;修改s的学号no为10006。函数调用语句strcpy(s−>name, ″Tom″);调用库函数strcpy修改s的姓名name为″Tom″。注意:a.no和s−>no访问的是同一对象,而s−>no和(∗s).no是等价的,其它成员类推,如图中所示。至此,当前fun的存储状态如下图所示。由于″Tom″短于″Johnson″,有几个字符未覆盖掉,这没有任何关系,因为′m′后的空字符′\0′足以标记″Tom″的结尾,后面的字符都是无意义的。

BLANK35-06

由于后面再无其它语句,函数fun返回,但无返回值,同时收回fun的存储空间。

函数fun返回后,main从挂起点即语句fun(&a);恢复继续执行,虽然fun无返回值,但通过指针s对结构体a的修改效果保留下来了。至此,当前main的存储状态如下图所示:

BLANK35-07

接着,执行下面的5条语句:

printf(″修改后的结构体为:\n″);
printf(″学号: %d\n姓名: %s\n″, a.no, a.name);
printf(″成绩:″);
for (i = 0; i < 3; ++i)
­       printf(″%5.1f″, a.score[i]);
printf(″\n″);

在标准输出设备上,给出提示,并将被修改后的结构体a的内容输出。由于这是main的最后语句,随即函数main执行结束、同时收回其存储空间。

知识点:

① 结构体是将若干相互关联的变量捆绑而成的集成体变量。例如:本题将学号、姓名和成绩捆绑成一个结构体,作为集成体来反映学生的多方面信息;还可以将2个浮点坐标变量集成一个结构体,表示几何平面上的一个点。

②  结构体类型定义的一种简单格式如下:

struct  结构体标签  {
­        成员1声明
­        成员2声明
­        ……
­};

例如:本题中的学生结构体类型定义:

struct stu {
­      int no;
­      char name[10];
­      float score[3];
};

其中stu叫做结构体标签,是一个标识符。

③ 结构体变量和结构体指针的一种简单声明格式如下:

类型名    变量名;

例如:int   a;     定义a为int类型的变量,

struct stu    a = {10002, ″Johnson″, 90, 84, 78};        定义a为struct stu类型的结构体变量并初始化,struct stu相当于int,都是类型名。

fun的形参声明struct stu  ∗s;     定义s为指针,指向struct stu类型的结构体变量,struct stu ∗相当于int ∗,都是指针类型名。

④ 若a是结构体变量,则只能利用圆点运算符访问结构体的成员。例如:a.no、a.name、a.score[2]。

⑤ 若s是结构体指针变量,则可利用−>或圆点运算符访问结构体的成员。例如:s−>no、s−>name、s−>score[2]或其等价式(∗s).no、(∗s).name、(∗s).score[2]。注意:其中的圆括号不能省,这是因为∗的优先级低于圆点。

⑥ 结构体和结构体指针均可作为函数参数被整体传递,也可作为函数值被整体返回,还可以整体赋值。而数组只能通过指针被函数间接访问,数组也不能整体赋值。

⑦ 库函数char ∗strcpy(char ∗s, char ∗ct)将串ct复制到字符数组s之中,包括串尾标记字符′\0′

练习题:

试将函数main中的变量a改名,fun的形参s改名,结构体标签stu改名,学号no改名,调通程序,使之得出同样的正确结果。

返回