可以将结构作为函数的参数,对结构进行操作。不要觉得要修改结构的值,就一定将结构作为地址值传递,这决定设计与使用函数的具体方法。
【例21.22】下面是把两个结构域的值相加作为另一个结构的域值供主程序使用,分析没有实现预定目标的原因,并修改程序实现预定功能。
#include <stdio.h>struct LIST{ int a,b;}d={3,8};void Add(struct LIST,struct LIST,struct LIST);void main(){ struct LIST e={5},f={0}; Add(d,e,f); //传结构变量的数值 printf(/"f.a=%d,f.b=%dn/", f.a,f.b); printf(/"f.a+f.b=%dn/", f.a+f.b);}//将结构作为参数,以传数值的方式传递这个参数void Add(struct LIST d,struct LIST e,struct LIST f){ f.a=d.a+e.a; f.b=d.b+e.b;}
【解答】程序将Add函数的结构f作为传数值的方式传递,当函数返回时,主程序里的参数不会被修改(f.a=f.b=0),所以没有完成预定功能。
可以有三种解决这个问题的方法。
1.改变参数f的传递方法
可以不修改Add函数的返回类型,即保留void类型,修改参数f的传递方法,将传数值改为传地址值,即将这个参数以指针方式传递。
//修改后的程序#include <stdio.h>struct LIST{ int a,b;}d={3,8};void Add(struct LIST,struct LIST,struct LIST*);void main(){ struct LIST e={5},f={0}; Add(d,e,&f); //传结构变量f的地址 printf(/"f.a=%d,f.b=%dn/", f.a,f.b); printf(/"f.a+f.b=%dn/", f.a+f.b);}//将结构f作为参数,以传地址值的方式传递这个参数void Add(struct LIST d,struct LIST e,struct LIST *f){ f->a=d.a+e.a; f->b=d.b+e.b;}
因为e.b=0,主程序中f的f.a=f.b=8,f.a+f.b=16。
2.将函数返回类型改为返回结构
可以不改变参数类型,而是将函数vid的返回类型改为struct类型。让Add函数返回结构f,使用“f=Add(d,e,f);”语句,实现对主函数结构f的修改。
#include <stdio.h>struct LIST{ int a,b;}d={3,8};struct LIST Add(struct LIST,struct LIST,struct LIST);void main(){ struct LIST e={5},f={0}; f=Add(d,e,f); //用结构f接收返回值 printf(/"f.a=%d,f.b=%dn/", f.a,f.b); printf(/"f.a+f.b=%dn/", f.a+f.b);}//将结构作为参数,以传数值的方式传递这个参数struct LIST Add(struct LIST d,struct LIST e,struct LIST f){ f.a=d.a+e.a; f.b=d.b+e.b; return f;}
3.将函数返回类型改为返回结构指针
#include <stdio.h>#include <stdlib.h>struct LIST{ int a,b;}d={3,8};struct LIST *Add(struct LIST,struct LIST,struct LIST);void main(){ struct LIST e={5},f={0}; f=*(Add(d,e,f)); printf(/"f.a=%d,f.b=%dn/", f.a,f.b); printf(/"f.a+f.b=%dn/", f.a+f.b);}struct LIST *Add(struct LIST d,struct LIST e,struct LIST f){ struct LIST *p; p=(struct LIST *)malloc (sizeof(struct LIST)); p->a=d.a+e.a; p->b=d.b+e.b; return p;}
一般是要在主程序中设计一个指针以接受函数返回的指针,例如
struct LIST *p;p=Add(d,e,f);
这种情况一般是在主程序中使用指针变量p,在本程序中,等于没有修改f的值域,这就要使用
printf(/"p->a+p->b=%dn/", p->a+p->b);
语句,这不合题意。为了修改f,所以直接使用
f=*(Add(d,e,f));
语句。因为“Add(d,e,f)”返回的是指针,所以“*(Add(d,e,f))”引用的是返回指针变量的值。所以在主程序中也没有使用指针的必要了。
不过,这种方法显得累赘,不如直接将f作为地址值传递简单,也就是第1种方法简单。所以说,要结合具体情况,选择最优设计。
4.需要注意的问题
这个程序完全是为了说明问题,针对这个程序,还有两个要注意的问题。
如果不给Add函数里的指针分配地址,则会出现一些问题。假如使用如下方式:
struct LIST *Add(struct LIST d,struct LIST e,struct LIST f){ struct LIST *p; p=&f; p->a=d.a+e.a; p->b=d.b+e.b; return p;}
表面上看来似乎可行。其实Add返回的指针是Add函数内的临时指针,也是不可靠的。这个地址里的值随时都会发生变化,运行结果甚至依赖主程序语句执行的顺序。
//不可靠的示范程序#include <stdio.h>#include <stdlib.h>struct LIST{ int a,b;}d={3,8};struct LIST *Add(struct LIST,struct LIST,struct LIST);void main(){ struct LIST e={5},f={0}; struct LIST *p=NULL; p=Add(d,e,f); printf(/"p->a=%d,p->b=%dn/", p->a,p->b); //1 printf(/"p->a+p->b=%dn/", p->a+p->b); //2 f=*p; printf(/"f.a=%d,f.b=%dn/", f.a,f.b); printf(/"f.a+f.b=%dn/", f.a+f.b);}struct LIST *Add(struct LIST d,struct LIST e,struct LIST f){ struct LIST *p=&f; p->a=d.a+e.a; p->b=d.b+e.b; return p;}
输出的错误结果如下:
p->a=8,p->b=8p->a+p->b=16f.a=4341788,f.b=16f.a+f.b=4341804
在第1次执行1~2打印语句时,结果正确。其实,这时候p指向的地址内容已经发生了变化,所以导致“f=*p;”赋值的结果错误,后面的输出当然也就错了。再看看下面主程序的运行结果就更清楚了。
void main(){ struct LIST e={5},f={0}; struct LIST *p=NULL; p=Add(d,e,f); f=*p; printf(/"p->a=%d,p->b=%dn/", p->a,p->b); //1 printf(/"p->a+p->b=%dn/", p->a+p->b); //2 printf(/"f.a=%d,f.b=%dn/", f.a,f.b); printf(/"f.a+f.b=%dn/", f.a+f.b); printf(/"p->a=%d,p->b=%dn/", p->a,p->b); printf(/"p->a+p->b=%dn/", p->a+p->b); printf(/"f.a=%d,f.b=%dn/", f.a,f.b); printf(/"f.a+f.b=%dn/", f.a+f.b);}
运行结果如下:
p->a=8,p->b=8p->a+p->b=16f.a=8,f.b=8f.a+f.b=16p->a=4345840,p->b=16p->a+p->b=4345856f.a=8,f.b=8f.a+f.b=16
先赋给f,因为f有自己的存储地址,所以两次打印的结果相同,但两次使用指针的结果就不一样了。所以一定要注意地址问题。
其实,Add的第3个变量是没有必要的,下面给出满足使用结构f的一种可靠的方法。
#include <stdio.h>#include <stdlib.h>struct LIST{ int a,b;}d={3,8};struct LIST *Add(struct LIST,struct LIST);void main(){ struct LIST e={5},f={0}; f=*(Add(d,e)); printf(/"f.a=%d,f.b=%dn/", f.a,f.b); printf(/"f.a+f.b=%dn/", f.a+f.b);}struct LIST *Add(struct LIST d,struct LIST e){ struct LIST *p; p=(struct LIST *)malloc (sizeof(struct LIST)); p->a=d.a+e.a; p->b=d.b+e.b; return p;}