【例21.23】函数参数传递变量值、地址值和指针的区别。
#include <stdio.h>void Add(int a, int *b, int *p){ printf(/"Add:&a=%#x,&b=%#x, p=%#xn/", &a, b, p); a = a + *b; *b = a * *b; *p = a + *b; printf(/"In Add:a=%d,b=%d, *p=%dn/", a, *b ,*p);}void main(){ int a=5, b=8, *p; p=&b; printf(/"main:&a=%#x,&b=%#x, p=%#xn/", &a, &b, p); printf(/"main:a=%d,b=%d, *p=%dn/", a, b ,*p); Add(a, &b, p); printf(/"main:a=%d, b=%d, *p=%dn/", a, b ,*p);}
程序运行结果如下:
main:&a=0x12ff7c,&b=0x12ff78, p=0x12ff78main:a=5,b=8, *p=8Add:&a=0x12ff1c,&b=0x12ff78, p=0x12ff78In Add:a=13,b=117, *p=117main:a=5, b=117, *p=117 //传值不改变变量a的值
由运行结果可以验证,在函数里,必须将传值的参数复制到函数里以完成形实结合,供被调函数使用,所以变量a在主函数和Add函数里的地址是不一样的,系统需要在被调用函数里为变量a重新分配地址,当离开函数时,又把函数里的a值丢掉,将原来调用时的形参值复制给变量a,即恢复原来的实参值。传递地址值和指针时,系统不为它们分配地址而仍然使用原来的地址,所以也不需要复制数据。同理,当调用返回时,也不需要复制数据。
【例21.24】函数参数传递结构变量值、地址值和指针的区别。
#include <stdio.h>#include <stdlib.h>struct LIST{ int a, b;};void Add(struct LIST a, struct LIST *pb, struct LIST *p){ printf(/"Add:&a=%#x,&b=%#x, p=%#xn/", &a, pb, p); a.a = a.a + pb->a; a.b = a.b + pb->b; p->a=pb->a + pb->a; p->b=pb->b+ pb->b; printf(/"In Add:a.a=%d, a.b=%dn/", a.a ,a.b ); printf(/"In Add:pb->a=%d, pb->b=%dn/", pb->a, pb->b ); printf(/"In Add:p->a=%d, p->b=%dn/", p->a, p->b );}void main(){ struct LIST a={1, 3}, b= {2, 4}, *p=&b; printf(/"main:&a=%#x,&b=%#x, p=%#xn/", &a, &b, p); printf(/"main:a.a=%d, a.b=%dn/", a.a ,a.b ); printf(/"main:b.a=%d, b.b=%dn/", b.a ,b.b ); printf(/"main:p->a=%d, p->b=%dn/", p->a, p->b ); Add(a, &b, p); printf(/"main:a.a=%d, a.b=%dn/", a.a ,a.b ); printf(/"main:b.a=%d, b.b=%dn/", b.a ,b.b ); printf(/"main:p->a=%d, p->b=%dn/", p->a, p->b );}
程序运行结果如下:
main:&a=0x12ff78,&b=0x12ff70, p=0x12ff70main:a.a=1, a.b=3main:b.a=2, b.b=4main:p->a=2, p->b=4Add:&a=0x12ff10,&b=0x12ff70, p=0x12ff70In Add:a.a=3, a.b=7In Add:pb->a=4, pb->b=8In Add:p->a=4, p->b=8main:a.a=1, a.b=3 //传值不改变结构变量a的值main:b.a=4, b.b=8main:p->a=4, p->b=8
由输出结果可知,结论与上例一样。
其实,通过汇编代码,可以清楚地看到在被调函数里如何将主函数结构变量的值复制给被调用的结构变量。
【例21.25】函数参数传递结构数组地址值和指针的例子。
#include <stdio.h>#include <stdlib.h>struct LIST{ int a, b;}a[2] = {{1, 3}, {2, 4}} , *p=a;void Add(struct LIST *pb, struct LIST *p){ int i = 0; printf(/"Add:&a=%#x, p=%#xn/", pb, p); for( i=0; i < 2; i++, p++) { a[i].a = a[i].a + p->a; a[i].b = a[i].b + p->b; } p=a; for( i=0; i < 2; i++, p++) { printf(/"In Add:a[i].a=%d, a[i].b=%dn/", a[i].a, a[i].b ); printf(/"In Add:p->a=%d, p->b=%dn/", p->a, p->b ); } p=a;}void main(){ int i=0; printf(/"main:&a=%#x, p=%#xn/", &a, p); for( i=0; i < 2; i++, p++) { printf(/"main:a[i].a=%d, a[i].b=%dn/", a[i].a ,a[i].b ); printf(/"main:p->a=%d, p->b=%dn/", p->a, p->b ); } p=a; Add(a, p); for( i=0; i < 2; i++, p++) { printf(/"main:a[i].a=%d, a[i].b=%dn/", a[i].a ,a[i].b ); printf(/"main:p->a=%d, p->b=%dn/", p->a, p->b ); }}
程序运行结果如下:
main:&a=0x423308, p=0x423308main:a[i].a=1, a[i].b=3main:p->a=1, p->b=3main:a[i].a=2, a[i].b=4main:p->a=2, p->b=4Add:&a=0x423308, p=0x423308In Add:a[i].a=2, a[i].b=6In Add:p->a=2, p->b=6In Add:a[i].a=4, a[i].b=8In Add:p->a=4, p->b=8main:a[i].a=2, a[i].b=6main:p->a=2, p->b=6main:a[i].a=4, a[i].b=8main:p->a=4, p->b=8
由此可见,如果数组维数大,使用结构指针比直接传递数组地址值更方便。