第二十二章  结构

22.1 面向对象的启蒙

22.2 结构/struct 的定义

22.3  . 操作符

22.4 -> 操作符

22.5 结构实例

22.6 结构与函数

  22.6.1 结构变量作为函数参数

    22.6.1.1 结构变量以传值的方式传递

    22.6.1.2 结构变量以传址的方式传递

    22.6.1.3 结构变量以常量传址方式传递

    22.6.1.4 兼容C:使用指针传递结构变量

  22.6.2 函数返回值是结构类型

22.7 作业

 

大家好课程拖了好久,大家急,我也急。今天是周末,一早去医院体检,被女医生扎了一针,胳膊上留下一个针眼。不禁想起一个真实的故事。一个我的同行程序员),和我差不多瘦。有一年夏天到南方出差,住在旅馆里一个晚上没睡好!为什么?因为蚊子又太多了啊几夜没睡好这可够倒霉的啦。谁知祸不单行。上了火车他困啊!卧铺上一歪他就睡着了,那只胳膊瘦瘦的,从睡铺上垂下来,露出被蚊子们叮的密密麻麻的红点。才睡不久,就被乘警叫醒带走——下铺的乘客去举报了,说吸毒青年

兄弟们,当程序员很苦!不过苦得值。当然身体要弄好。

 

22.1 面向对象的启蒙

 

我们以前学习了各种数据类型的变量。先来复习一下。

变量做什么用?程序用来变量来存储数据,用它来表达真实世界中的事物

 

比如:假设我最近开了一家幼儿园,园里有一群小娃娃。娃娃的家长们把孩子交给我们之后,都要求我们要时时关心孩子们的“健康成长”,因此我们不得不为每个孩子建一个入园档案。档案记载每个孩子的一些数据。

 

//娃娃的名字:

char xingMing[11];  //姓名最长5个汉字,占用10字节,多留一个字节用于存放'\0'

 

//娃娃的身高:

int shenGao; //单位 cm

 

//体重:

float tiZhong; //单位 公斤

 

我们知道,世界的万事万物,去除一些无用的修饰,可以表达为“数据”和“操作”。比如:我吃饭,“我”和“饭”是数据,而“吃”是一种动作,一种操作。对应到编程语言,就是“数据”和“流程”。那么,当我们写程序来解决某一现实问题时,应该先考虑的“数据”,还是“流程”呢?多数问题,应该先去考虑“数据”。也就是说,当遇上一个现实问题,我们应先去“抽取”这个问题的数据,考虑如在程序中表达,设计,定义这些数据。然后再去设计流程。

 

以我们上面的幼儿园管理的例子,我们现在已经差不多抓出相关的数据。不过,上面所做的,只是“一个孩子”的数据,幼儿园里的孩子当然不会只有一个。还好,我们学过数组,不是吗? 所以,我们将上面的变量定义改一改。

 

先定义一个宏,假设园里有30名宝宝。

 

#define BAOBAO_GESHU 30  //30个宝宝

 

//30个宝宝,要30个名字:

char xingMing[BAOBAO_GESHU][11]; //忘了二维数组?呵呵。复习一下。

 

//30个宝宝,30个身高:

int shenGao[BAOBAO_GESHU];

 

//30个宝宝,30个体重:

float tiZhong[BAOBAO_GESHU];

 

假设我们的程序具备打印功能。这样每一天放学时,我们都在宝宝走出校门前,将他或她称量一番,得出体重,身高。记录到我们的程序,然后程序再打印出一张小纸条。贴在宝宝后脑勺,供宝宝妈妈参考……哈哈,我们可以把这个小程序卖给本市的300家幼儿园,每份卖400元,300家就是 400 * 300 = 120000元……流口水中……

 

擦干口水回过神,来开始我们的今天最重要的学习:面向对象的启蒙。

什么叫面向对象,我且不解释。不结合实例子,解释也没有用啊。

 

一个人,有眼睛、鼻子、嘴、头发、四肢。也就是说,“人”是一种“数据”,而“鼻子”,“嘴”,“头发”等也各自是一种数据,彼此之间具备不同的“数据类型”。但是在多数情况下,“人”是一种不可再分的整体(医院里负责解剖的人所做的事不在我们所说的多数情况之内)。扯到编程上而来 ,当我们想用程序管理30个人时,我们应该是定义一个数组,存储30个人,而不是分开来定义成:30个眼睛[2]、30个鼻子、30个头发[1000],30个四肢。

 

回到幼儿园程序。每个宝宝都有身高、体重、姓名这些属性;宝宝也应作为一个整体,而不是像上面那样分开来定义。

 

这就是面向对象的第一个启蒙: 面向对象,是为了让我们把程序写得更“自然而然”。越是支持面向对象的编程语言,我们就越能以接近人类自然逻辑的思路来设计程序;而越不支持面向对象的编程语言,也许它初看起来似乎很浅显 易用,但当用它来解决实际问题时,程序员就不得不受限于这门语言特有的解决问题的思路。

 

说完面向对象的好处,我们必须马上来做几个问题的“纠偏”。

 

第一、面向对象并不代表解决问题的最高效率。

 

确实地这样的。“面向对象”被提出,是因为某些问题实在太庞大太复杂了,人类的写程序解决这些问题时,一会儿就胡涂了,晕了,搞错了,于是希望有一种方法来让程序员不会那么快在一堆代码前精神崩溃。这才提出了“面向对象”。所以在我们第一次接触到这个概念时,请先记住,和我们前面所讲 的一样,比哪为什么要有变量,为什么要有数据类型:编程语言设计的不断改进,都是为了迁就人类的“容易犯错”或“天生懒惰”。否则,如果只是要追求最高效率 ,如果人类有着机器般的脑,编程语言根本不需要有C,C++,JAVA,C#什么的,甚至连汇编也不需要,只需要一个机器语言就可以。“面向对象”的编程思想迁就我们什么呢?它迁就人类总是喜欢以比较自然的方式来解决问题。

 

先来考虑,“自然而然”的事,不一定是最高效率。这很多,比如,路口的红绿灯制度,显然不是最高效率。最高效率其实应该是闯红灯。你会说,闯红灯会出车祸,出车祸不就堵车?造成效率低了?哦,其实我是要说:如果每个司机,行人都闯红灯,并且能保证不撞到其它车或行人,那么路口上车辆穿行的效率肯定最高。可惜,驾驶员做不到这一点,所以只好有红绿灯。

 

第二、虽然说面向对象是“很自然的事”,但我们仍然要花力去学习。

 

古人老子说:“道法自然”。那什么叫“自然”啊?

这里的自然也是有规定的,并不是人类的所有行为都称为“自然”的,也不一定是你习惯的行为就自然,你不习惯的行为就不自然。比如人家都觉得“饭前便后要洗手”,可若你偏要认为这种行为太不自然,太做作,那我们也没有办法。

另外,人类解决现实生活中,有时也要追求点效率。比如,酒家承办婚礼,要准备10桌一样的酒席。每一桌上面都有这道菜那道汤的。我们可以把完整的一桌酒菜看成一个“整体”。但大厨们可不这样认为,我猜他们在准备时,一定是先把某道菜一块儿做好10桌的份量,然后做下一道菜,而不是我们认为的,先办好一桌,再办下一桌。对于我们,一桌一桌菜是自然的,而对做的人来说,一道一道菜才是自然的。

如何设计一个面向对象的程序,并且保证一定的高效率,这是一门无止境的科学,我们需要不断地学习。面象对象源于生活,而高于生活。

 

说了这么多,大家不要被“面向对象”吓坏了。今天我们所要学习的面向对象的设计方法,很简单:把同属于一个整体的“数据”,归成一个新的类型去考虑,而不是分割成每一部分。

 

22.2 结构/struct 的定义

 

“结构”提供一种能力,允许程序员把多个数据类型,归属成一个完整的,新的数据类型。

 

以上面的幼儿园管理程序为例,我们可以定义出这样一个新的数据类型:

 

struct BaoBao

{

    char xingMing[11];

    int shenGao;

    float tiZhong;

}; //<----注意,以分号结束定义

 

现在,我们有了一种新的数据类型,叫 BaoBao 结构。该数据类型由三个变量的定义组成。分别是xingMing[10], shenGao, tiZhong。这三个组成变量,我们称为该结构的“成员变量”。

 

既然 BaoBao 是一种数据类型,我们就可以定义一个该类型的变量:

 

BaoBao daBao; //daBao 是一个“BaoBao”类型的变量。

 

这个过程,和我们定义一个整型变量,并无多大区别:

 

int a;

 

我们记得不同数据类型的变量,有着不同的大小(占用内存的大小)。

比如:一个bool或一个char类型的变量,占用一个字节,而一个int类型则占用4个字节的内存;

后来我们又学习数组,数组的大小除了和它的数据类型有关外,还有数组元素的个数有关。比如:char xingMing[11]占用11个字节,而int txZhong[30]占用4 * 30个字节

最后,前面的几章内,我们又学习了指针。指针类型固定占用4个字节。这是因为不管什么类型的指针,都是要用来存储一个内存地址,而在32位的计算机上,内存地址的大小固定为4字节(8 * 4 = 32位)

 

这一切我们可以用 sizeof 来验证:

 

int s1 = sizeof(char);

int s2 = sizeof(int);

int s3 = sizeof(char *);

 

int arr[10];

int s4 = sizeof(arr);

 

上面的程序执行后,s1到s4分别为:1,4,4,40

 

现在我们来问,我们自定义的 BaoBao 数据类型,它的大小是多少?换句话,也可以问:做出如下定义之后:

 

BaoBao daBao;

 

daBao这个变量“吃”掉了多少字节的内存呢?

 

我们再看一次 BaoBao 这个结构的定义:

 

struct BaoBao

{

    char xingMing[11];

    int shenGao;

    float tiZhong;

};

 

直观上猜测,BaoBao这个结构由三个成员变量组成,那么它的大小应该就是这三个成员变量大小之和。这个猜测颇有道理,如果它是正确的话,那么,sizeof(BaoBao) 应等于 11 + 4 + 4 = 19;

 

让我们打开CB6,然后新建一个控制工程。然后在 Unit1.cpp 里增加一些代码,使之看来如下(黑体部分为需要增加的代码)

 

//---------------------------------------------------------------------------

#pragma hdrstop

#include <iostream.h>
 

//---------------------------------------------------------------------------

struct BaoBao

{

   char xingMing[11];

   int shenGao;

   float tiZhong;

};
 

#pragma argsused

int main(int argc, char* argv[])

{

   int size = sizeof(BaoBao);
 

   cout << "SizeOf struct BaoBao = " << size << endl;

 

   system("PAUSE");
 

   return 0;

}

//---------------------------------------------------------------------------
 

按F9后看到运行结果:

sizeof BaoBao

奇怪,BaoBao 结构的大小,竟然是20。比我们猜测的19,多出了一个字节?

 

 

事情是这样的。就像我们去小店买东西,假设有一天我们要去赶飞机,走之前去小店买了点食品,总价19元,店老板没有1元钱,于是我们为了能快点出发,就直接给他20元, 告诉他不用找零钱了。

 

为了效率,编译器也会有类似的动作。这称为结构的“字节对齐”,当然,这个对齐方法要比我们的19取整到20复杂一点。关于编译器是通过什么规则来把一个结构进行扩展,我们留在本章的增补课程中。这里只需记住,对于一个结构的大小,一定要用sizeof才能得到它的实际大小。当然,可以肯定的是,结构的大小一定是大于或等于其所有成员变量的大小之和

 

现在我们知道,定义了一个BaoBao的变量(daBao),就会在吃掉20个字节的内存。接下来我们来看,如何使用 daBao 这个变量呢?

 

22.3  . 操作符

 

通过点操作符,我们可以得以一个结构中的成员变量。

请看例子:

 

BaoBao daBao; //定义一个 BaoBao 类型的变量,变量名为daBao;

 

daBao.shenGao = 83; //“大宝”的身高是83公分

daBao.tiZhong = 14; //体重是14公斤

 

//字符串用strcpy函数来设置

strcpy(daBao.xingMing, "大宝");

 

.操作符,可以理解为“的”。不是吗? daBao.shenGao ,就读成 “大宝的身高”,多么的“自然而然”啊!今天我们已经摸到“面向对象”编程世界的门环了。

 

22.4 -> 操作符

 

结构变量也可以是一个指针:

 

BaoBao* pDaBao; //定义一个 指向“BaoBao”结构的指针

 

考一下,pDaBao占用几个字节的内存,如果你回答是:20,那真该自己绝食一顿。:(

 

指针的大小总是只有4个字节。指向“结构”的指针也如此。我们可以通过 new 操作符来为一个指针分配实际内存:

 

pDaBao = new BaoBao;

 

这一点,和我们定义一个int 型指针,然后为它分配内存的操作一致:

 

int* pInt = new int;

 

pInt分配后,指向一块大小为sizeof(int)的内存,而pDaBao分配后,指向一个大小为sizeof(BaoBao),的内存。

 

对于指向结构的指针变量,要取得相应结构内的成员变量,必须通过以下语法:

 

(*pDaBao).xingMing;

(*pDaBao).shenGao;

 

从语法上分析,你必须先复习一下《指针》章节中,关于*用法与意义。*pDaBao 得到指针实际向的结构变量,然后再进行点操作符,得到该结构变量内的某一成员。

 

不过上面的写法显然很繁琐。简化方法是使用 -> (可读作箭头操作符 ,或指向操作符,或者就叫“减大于”吧)

 

pDaBao->xingMing;

pDaBao->shenGao;

 

也就是说,如果一个变量是结构变量,那么它可以直接用.来取得它的成员。而如果变量是一个结构的指针,那么可以请用 ->来得到它的成员。

 

顺便说一句,为一个指向结构的指针变量分配的内存,当不再需要时,同样需要记得释放:

 

//定义指针,并分配内存:

BaoBao *pDaBao = new BaoBao;

 

//为各成员赋值:

pDaBao->shenGao = 171;

pDaBao->tiZhong = 13.5;

strcpy(pDaBao->xingMing,"大宝");

 

//输出:

cout << pDaBao->xingMing << "的身高为: " << pDaBao->shenGao << endl;

cout << pDaBao->xingMing << "的体重为: " << pDaBao->tiZhong << endl;

 

//释放:

delete pDaBao;

 

22.5 结构实例

 

例子中,我们要求老师输入5个宝宝的数据,然后程序将这5个宝宝的情况打在屏幕上:

 

打开CB,新建一个控制台工程。

 

因为需要输入输出,所以先在Uint1.cpp中加下以下黑体部分:

 

#pragma hdrstop

#include <iostream.h>
 

然后是定义BaoBao结构:

 

//---------------------------------------------------------------------------

struct BaoBao

{

    char xingMing[11];

    int shenGao;

    float tiZhong;

};  //分号结束结构的定义

 

为了方便演示,我们只让有5个宝宝,在上面的结构定义代码后面加一行:

 

#define BAOBAO_GESHU 5  //宏定义之后没有分号

 

然后,我们需定义一个BaoBao数组变量:

 

int main(int argc, char* argv[])

{

   BaoBao baoBao[BAOBAO_GESHU];

  

    return 0;

}
 

程序一开始时,我们要求幼儿园老师输入这五个宝宝的数据:

 

int main(int argc, char* argv[])

{

   BaoBao baoBao[BAOBAO_GESHU];

  

   for (int i = 0; i < BAOBAO_GESHU; ++i)

   {

      cout << "请输入第 " << i + 1 << "个宝宝的数据" << endl;

 

      cout << "姓名:";

      cin >> baoBao[i].xingMing;

 

      cout << "身高:";

      cin >> baoBao[i].shenGao;

 

      cout << "体重:";

      cin >> baoBao[i].tiZhong;

   }

 

   return 0;

}

 

运行上述程序,我们就可以进行输入了。注意,名字不可以超过5个汉字,否则程序将可能发生不可预料的错误。

 

最后,再一个循环,我们将5个宝宝的数据输出:

 

int main(int argc, char* argv[])

{

   BaoBao baoBao[BAOBAO_GESHU];

  

   for (int i = 0; i < BAOBAO_GESHU; ++i)

   {

      cout << "请输入第 " << i + 1 << "个宝宝的数据." << endl;

 

      cout << "姓名:";

      cin >> baoBao[i].xingMing;

 

      cout << "身高:";

      cin >> baoBao[i].shenGao;

 

      cout << "体重:";

      cin >> baoBao[i].tiZhong;

   }

 

   for (int i = 0; i < BAOBAO_GESHU; ++i)

   {

      cout << " " << i + 1 << "个宝宝的数据如下" << endl;

 

      cout << "姓名:" << baoBao[i].xingMing << endl;

 

      cout << "身高:" << baoBao[i].shenGao << endl;

 

      cout << "体重:" << baoBao[i].tiZhong << endl;

   }

 

   system("Pause");

 

   return 0;

}

 

运行结果略。

 

22.6 结构与函数

 

int foo(int a); 是一个函数,其中a是参数,返回值是一个整数。

假充foo的实现如下:

 

int foo(int a)

{

   return a * 2;

}

 

那么, 代码:

 

int b = foo (100); 将使b值为200。 请参看专门函数专门章节。本章中,我们将分别讲如何在参数及返回值中使用结构变量。

 

22.6.1 结构变量作为函数参数

 

函数的参数有两种传递方法,一种是传值,一种是传址。如果您觉得有些陌生了,那一定要复习一下函数参数的相关章节。

 

我们先来定义一个结构,这个结构用于表达一个四边形(SiFangXing)

 

struct SiFangXing

{

    int l1,l2,w1,w2;  //四方形的四条边

};

 

现在我们要做两道题:

 

第一道:写一个函数,对所给的四方形求周长。

第二道:写一个函数,将所给的四方形长宽各增加一倍。

 

请大家在下面小节中,注意两个函数的参数形递有何不同,并思考各自的目的。

 

22.6.1.1 结构变量以传值的方式传递

 

第一道:写一个函数,对所给的四方形求周长。

 

//求周长:

int QiuZhouChang(SiFangXing sfx)

{

    return sfx.l1 + sfx.l2 + sfx.w1 + sfx.w2; //四边之和即是周长

}

 

22.6.1.2 结构变量以传址的方式传递

 

第二道:写一个函数,将所给的四方形长宽各增加一倍。

 

//加倍长宽

void JiaBeiChangKuan(SiFangXing& sfx)

{

   //各边都*2;

   sfx.l1 *= 2;

   sfx.l2 *= 2;

   sfx.w1 *= 2;

   sfx.w2 *= 2;

}

 

22.6.1.3 结构变量以常量传址方式传递

 

在22.6.1例中,由于我们并不需要在求周长的函数内改变所传入的四方形,所以我们采用“传值”方式。传值将复制一份实参,然后把“复制品”传给函数。这样就有了一个问题。以前我们写的函数的参数,多是像int,char之类的简单变量,它们占用的内存并不多,复制也快。但今天我们学习结构,结构往往由多个成员变量组成,占用内存较大,如果复制一份,就会显得浪费。并且,占用内存大的结构,在复制起来,比较占用时间。真是时间和空间双重浪费。

 

怎么办呢?首先想到的是,那就改成传址啊——

 

int QiuZhouChang(SiFangXing& sfx)

{

    return sfx.l1 + sfx.l2 + sfx.w1 + sfx.w2; //四边之和即是周长

}

 

采用传址方式后,传递给参数的,其实是实参的地址。而地址的大小只需要4个字节,相当于传一个整形数,又小又快。双重浪费的问题算是解决。但是这却带来了一个“隐患”。如果写QiuZhouChang函数的人一不小心,在该函数内修改了传入的参数,就会造成程序难以查找的错误:

 

int QiuZhouChang(SiFangXing& sfx)

{

   int zc = sfx.l1 + sfx.l2 + sfx.w1 + sfx.w2; //四边之和即是周长

 

   sfx.l1 *= 2;  //当时写这个函数的程序员发高烧,所以有了这行代码 :)

 

   return zc;

}

 

上面函数显然是错误,对一个四方形求周长的函数,怎么可以莫名地修改人家四方形的边长呢?并且由于参数我们在前面改为用“传址”方式,所以当一个四方形求完周长后,它的边长1竟然长了一倍长……

 

...

SiFangXing sfxA; //四方形A

sfxA.l1 = sfxA.l2 = 10; //长10

sfxA.w1 = sfxA.w2 = 5;  //宽5

 

//求周长之前,输出四边长:

cout << "四边长:" << sfxA.l1 << "," << sfxA.l2 << ","

       << sfxA.w1 << "," << sfxA.w2 << endl;

 

int zhouChang = QiuZhouChang(sfxA); //求周长

 

cout << "周  长:" << zhouChang << endl;

 

//求周长之后,再输出四边长:

cout << "四边长:" << sfxA.l1 << "," << sfxA.l2 << ","

       << sfxA.w1 << "," << sfxA.w2 << endl;

...

 

上面的代码输出结果是:

 

四边长:10,10,5,5

周  长:30

四边长:20,10,5,5

 

你可能会说,我绝不会在发高烧时写代码,但要知道,如果一个函数体内的代码足够复杂,那么每个人都有可能在不发高烧的情况下,也写出愚蠢的代码来。C++提供了一种方法,让我们可更好的避免此类错误代码。这就是我们所说的“常量传址”。

 

//传址常量形式的参数

int QiuZhouChang (const SiFangXing& sfx)

{

   return sfx.l1 + sfx.l2 + sfx.w1 + sfx.w2;

}

 

1、上述参数形式中,参数 sfx 将以传址的方式来传递。传址方式避免了参数复制品造成的内存与速度的问题。符号“&”标明了它是使用传址。

2、const 修饰符 则指明 sfx 将被当作常量对待,该语法规定你不能在当前函数内修改这个参数——不管你是否发高烧。

 

请在CB时试着写下面的高烧代码:

 

int QiuZhouChang(const SiFangXing& sfx)

{

   int zc = sfx.l1 + sfx.l2 + sfx.w1 + sfx.w2; //四边之和即是周长

 

   sfx.l1 *= 2;  //编译时,该行会报错

 

   return zc;

}

 

编译器将拒绝通过上述代码。

 

趁热打铁,我们再来一个“常量传址”例子,就是上面的输出四方形各边长的代码:

 

//输出指定四方形的四边长:

void ShuChuSiBianChang(const SiFangXing& sfx)

{

   cout << "四边长: " << sfx.l1 << "," << sfx.l2 << "," << sfx.w1 << "," << sfx.w2 << endl;

}

 

像类似上述的两个函数参数,你可以拒绝使用 “&” 来指定使用传址;你也可以拒绝使用 const 来限制它是一个常量。你的代码可以工作,但它们效率不好;并且,你的代码越来越多时,你犯错误的机率很可能急剧地升高,直到整个程序乱成一团。

 

程序员要养成良好习惯。否则除了上述的问题外,当你与其他具备良好习惯的程序员一起写程序时,你会发现你的代码将无法和别人的代码很好地衔接,甚至不“兼容”。

 

C++ 和其它语言相比,就是它提供了很多强大的语法功能,但它并不强制你使用。其它的语言,有的是提供了同样的语法功能,并强制你使用;而有些则缺少必要的语法。之所以C++是现在这个样子,有它的历史原因,比如说它必须兼容C语言。

 

22.6.1.4 兼容C:使用指针传递结构变量

 

C 当然也只持最普通的“传值”方式:

 

int QiuZhouChang (SiFangXing sfx)

{

   return sfx.l1 + sfx.l2 + sfx.w1 + sfx.w2;

}

 

但前所言,“传值”有双浪费之弊。我们坚决反倒。微软的程序员也坚决反对——可以 Windows 中很大一部分就是拿C写的。而C既不支持使用“&”来实现传址方式,也不支持 const 修饰为“常量”。怎么办?答案可能很出乎你的意料:没办法。象写操作系统这类程序,“效率”永远是重中之重,所以只要冒着程序有层出不穷的BUG的危险,只考虑如效率了。

 

在 C 语言时,要实现传址,方法就是用指针。C++ 兼容这一点。

 

int QiuZhouChang(SiFangXing* psfx)

{

   return psfx->l1 + psfx->l2 + psfx->w1 + psfx->w2;  // . 换成了 ->,因为psf是指针

}

 

调用时,如果实参不是一个指针,就使用 & 来取址:

 

...

SiFangXing* sfxA;

sfxA.l1 = sfxA.l2 = 10;

sfxA.w1 = sfxA.w2 = 5;

 

int zc = QiuZhouChang(&sfxA); //& 用于得到sfxA地址

 

传指针就是传地址。效率问题解决了,但“高烧”代码编译器不会指出:

 

int QiuZhouChang(SiFangXing* psfx)

{

   int zc = psfx->l1 + psfx->l2 + psfx->w1 + psfx->w2;  // . 换成了 ->,因为psf是指针

 

   psfx->l1 *= 2;

 

   return zc;

}

 

编译器会认为,或许这就是你原来想要的。事实上,编译器读不懂英语,更不懂得中国拼音,它,怎么知道你是“QiuZhouChang”函数是要“求周长”呢?:P

 

22.6.2 函数返回值是结构类型

 

函数的返回值也可以一个结构变量。

 

让我们来实现这么一个功能:把四方形A 和四方形B相加,得到四方形C。相加的方法是长+长,宽+宽。

 

SiFangXing AddSiFangXing (const SiFangXing& aSfx, const SiFangXing& bSfx)

{

   SiFangXing cSfx;

 

   cSfx.l1 = aSfx.l1 + bSfx.l1;

   cSfx.w1 = aSfx.w1 + bSfx.w1;

 

   cSfx.l2 = aSfx.l2 + bSfx.l2;

   cSfx.w2 = aSfx.w2 + bSfx.w2;

 

   return cSfx;

}

 

调用样例为:

 

...

SiFangXing a,b,c;

 

a.l1 = a.l2 = 10;

a.w1 = a.w2 = 5;

 

b.l1 = b.l2 = 20;

b.w1 = b.w2 = 18;

 

c = AddSiFangXing ( a, b );

 

ShuChuSiBianChang(c); //输出,见22.6.3

...

 

上这代码结果为:

四边长: 30,30,23,23

 

22.7 作业

 

一、本章中的所有例程,请都在CB上演练一番。

二、写一个求四方形面积的函数。

三、请写一个将四方形长和宽对调的函数。

四、请写一个函数,输入两个四方形,返回其中面积较大者。

五、请定义一个“圆”的结构。并写相应的三个函数实现:1、求圆周长,2、求圆面积,3、让指定的圆周长增加一倍。