首页 » C语言解惑 » C语言解惑全文在线阅读

《C语言解惑》21.3 使用结构作为函数的参数

关灯直达底部

要注意传递结构变量和结构数组的区别。

21.3.1 结构变量的传数值与传地址值

【例21.13】分析下面程序传数值和传地址值的区别。


#include <stdio.h>struct List {            int a,b;            double c;}ag,ad,*p;void Add(struct List );void disp(const struct List *);void Add1(struct List *);int main ( ){     ag.a=25; ag.b=30; ag.c=45;     ad.a=8;     p=&ag;     disp(&ag);     Add(ag);     disp(&ag);     Add1(&ag);     disp(p);     Add1(p);     disp(p);     return 0;}void Add(struct List s){ s.a=s.a+s.b;}void Add1(struct List *s){ s->a=s->a+s->b;}void disp(const struct List *f) { printf(/"%3d %3d %lfn/", f->a,f->b,f->c); }  

运行结果如下。


25  30 45.00000025  30 45.00000055  30 45.00000085  30 45.000000  

【解释】传递结构变量有传数值和地址值之分,传递数值不会改变实参的值,传递地址值是改变实参的必要条件,但不是充分条件,如disp函数的参数是指针,但不会被改变。

传地址时,实参以地址和指针的形式赋给形参均是等价的。形参设计为指针,程序中不一定非要声明指针参数,使用地址值即可。

对不允许改变的参数,可以设计为const类型,如disp函数。

21.3.2 结构数组传地址值

【例21.14】演示传递结构数组的例子。


#include <stdio.h>struct List {            int a,b;            double c;}arg[4],*p;void Add(struct List );void disp(const struct List *);int main ( ){     p=arg;     arg[0].a=87; arg[0].b=58; arg[0].c=5.8;     arg[1].a=15; arg[1].b=25; arg[1].c=2.5;     Add(arg);     disp(p);     p->a=33;     Add(arg);     disp(arg);     return 0;}void Add(struct List s){     s[2].a=s[0].a+s[1].a;     s[2].b=s[0].b+s[1].b;     s[2].c=s[0].c+s[1].c;     *(s+3)=*(s+1);   //元素整体赋值}void disp(const struct List *p) {     int i;     for(i=0;i<4;i++)         printf(/"%3d %3d %lfn/", (p+i)->a,(p+i)->b,(p+i)->c); }  

程序运行结果如下。


 87  58 5.800000 15  25 2.500000102  83 8.300000 15  25 2.500000 33  58 5.800000 15  25 2.500000 48  83 8.300000 15  25 2.500000  

【解释】因为结构数组的名字就是结构存储的首地址,所以用名字和指针都是传递的地址值,所以要特别小心,不要修改不需要改变的参数值。对不允许改变的函数参数,推荐使用const限定词。一定要注意,所谓改变,就是被用来做左值。

对于使用结构数组作为参数的函数而言,形参既可以使用数组,也可以使用指针,只要使用的方法按照给定参数形式正确设计即可,至于程序中的实参用哪种形式进行实参与形参的结合,都是无关紧要的,因为它们都是可以正确工作的。使用中切记不要围着函数的设计转悠,本例清楚地演示了这个问题。

如果结构成员很多,生成副本会很费时间,这时推荐使用指针。

【例21.15】传地址值并不改变参数的例子。


#include <stdio.h>struct List {            int a,b;            double c;}arg[2];void Add(struct List *);void disp(const struct List *);int main ( ){     arg[0].a=87; arg[0].b=58; arg[0].c=5.8;     arg[1].a=15; arg[1].b=25; arg[1].c=2.5;     Add(arg);     disp(arg);     return 0;}void Add(struct List *s){     int i,sum=0;     double total=0.0;     disp(s);     for(i=0;i<2;i++){          sum=sum+s[i].a +s[i].b;          total=total+s[i].c;     }     printf(/"整数之和为:%d,实数之和为%lf。n/",sum,total);     printf(/"总和为:%lf。n/",sum+total);}void disp(const struct List *p) {     int i;     for(i=0;i<2;i++)         printf(/"%3d %3d %lfn/", (p+i)->a,(p+i)->b,(p+i)->c); }  

程序运行结果如下。


87  58 5.80000015  25 2.500000整数之和为:185,实数之和为8.300000。总和为:193.300000。87  58 5.80000015  25 2.500000  

【解释】本例更清楚地演示了传递地址值只是改变参数的必要条件。下面将本例的传结构数组改为传指针,进一步说明了设计和使用的配合问题。

【例21.16】在下面的参数传递中,能否改用f1(arg)的形式?举例说明如何改写函数才能使用结构参数。


#include <stdio.h>struct List {            int a,b;            char ch;            double z;} arg[4],*p;void fl(struct List *);int main ( ){     arg[1].a=1000;     arg[0].z=98.9;     printf(/"input arg[1].z=/");     scanf(/"%lf/",&arg[1].z);     p=arg;     fl(p);     return 0;}void fl(struct List *p) {     printf(/"%dn/", (p+1)->a);     printf(/"%f %fn/", p->z,(p+1)->z); }  

【解答】假设输入35.8,运行示例如下。


input arg[1].z=35.8100098.900000 35.800000  

这里是用结构的指针作为形参传递给函数。虽然函数要求的是指针,但结构名arg就是结构存储的首地址,所以本程序不需要修改,直接使用


f1(arg)  

的形式是完全正确的。

建议:在设计结构时,如果有键盘人机交互,应尽量避免使用字符和字符指针。使用字符串时,也要预防可能对读取字符串产生的干扰。

注意:如果输入的字符串中需要空格,不能使用scanf函数,可以使用gets函数。