可以将结构作为函数的参数,对结构进行操作。不要觉得要修改结构的值,就一定将结构作为地址值传递,这决定设计与使用函数的具体方法。
【例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=8
p->a+p->b=16
f.a=4341788
,f.b=16
f.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=8
p->a+p->b=16
f.a=8
,f.b=8
f.a+f.b=16
p->a=4345840
,p->b=16
p->a+p->b=4345856
f.a=8
,f.b=8
f.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
;
}