设计函数一定要明确函数的返回值,只有明确返回值才能确定函数的类型。函数返回值和参数是两回事。参数是指函数参数表中的变量,这个变量视传递方式而变。传数值不改变参数的值,而传地址值是改变参数值的必要条件,但是否改变,则视使用方法而定。函数返回值是指被调用函数结束时所返回的值,非void类型的返回值就是return后面表达式的值。返回值的设计就是要保证调用它的函数正确接收这个值。
6.7.1 无返回值的void类型函数
虽然void类型函数不返回值,但并不说明它不能提供中间值。
【例6.9】找出下面程序中的错误。
#include <stdio.h>void max(int , int ); //函数参数采用传数值方式int main(){ int a, b,c; printf(/" 输入两个整数:/"); scanf(/"%d %d/",&a,&b); c=max(a,b); return 0;}//将变量作为参数,以传数值方式传递参数void max(int a, int b){ if(a<b) printf(/"最大值是:%dn/",b ); else printf(/"最大值是:%dn/",a );}
【解答】max没有返回值,它直接输出求值结果,不能将它赋值给c。删除变量c的声明,然后直接使用语句“max(a,b);”即可。这种调用方式称为直接调用函数语句。
【例6.10】找出下面程序中的错误。
#include <stdio.h>void max(int , int ); //函数参数采用传数值方式int main(){ int a, b,c; printf(/" 输入两个整数:/"); scanf(/"%d %d/",&a,&b); max(a, b); //传数值 printf(/"最大值是:%dn/",c ); return 0;}//将变量作为参数,以传数值方式传递参数void max(int a, int b){ if(a<b) c=b; else c=a;}
【解答】max函数使用的是主函数里的变量c,这是错误的。在主函数之外将c声明为全局变量即可。这时虽然也是函数语句调用,但被调函数改变全局外部变量的值。一定要注意:void函数没有返回值,但它可以改变外部变量的值。虽然一般不提倡使用这种方法,但在某种场合下还是很有用的。因为它简化了函数本身的设计,如果已经存在外部变量,为何不好好利用呢?函数可以使用外部变量,所以可直接将结果赋给外部变量。主函数就可以使用外部变量的值。
注意外部变量名不能与函数的变量名相同。在上例中,如果声明全局变量c,而没有去掉主程序的变量c,就会出错。
【例6.11】为何下面的程序计算的结果不对?
#include <stdio.h>void max(int , int ,int);int main(){ int a, b,c; printf(/" 输入两个整数:/"); scanf(/"%d %d/",&a,&b); max(a, b,c); c=a+b+c; printf(/"c=%dn/",c ); return 0;}void max(int a, int b,int p){ if(a<b) p=b; else p=a;}
【解答】max的第3个参数要设为指针参数。修改后的程序如下:
#include <stdio.h>void max(int , int ,int*);int main(){ int a, b,c; printf(/" 输入两个整数:/"); scanf(/"%d %d/",&a,&b); max(a, b,&c); c=a+b+c; printf(/"c=%dn/",c ); return 0;}void max(int a, int b,int * p){ if(a<b) *p=b; else *p=a;}
【例6.12】下面程序在函数原型的声明中,对数组采用两种不同的声明,哪个声明是正确的?所设计的函数类型是无返回值的void类型,程序想对数组a的元素数值反序,设计为void类型能行吗?
#include<stdio.h> //预编译命令void Exch(int *);void Display(int [ ]);int main(){ int a={1,3,5,7,9}; Display(a); Exch(a); Display(a); return 0;}void Exch(int a[ ]){ int c; c=a[0]; a[0]=a[4]; a[4]=c; c=a[1]; a[1]=a[3]; a[3]=c;}void Display(int a[ ]){ int i; for( i=0;i<5;i++) printf(/"%d /", a[i]); printf(/"n/");}
【解答】对数组而言,数组名就是首地址的指针,所以两个格式都是可以的。
void类型的函数是说函数没有返回值,并不是说void类型的函数不能改变传递的参数值。函数的返回值不能是数组,但可以将数组作为参数以传地址值的方式传给被调函数,由被调函数通过存储数组的地址修改数组元素的值。
程序运行结果如下:
1 3 5 7 99 7 5 3 1
6.7.2 函数返回值问题
1.非void类型的函数必须返回一个值
【例6.13】下面的程序用来改变字符数组的内容。
#include <string.h>#include <stdio.h>int st( char );int main( ){ char s=/"Good Afternoon!/"; printf(/"%sn/", s); st(s); printf(/"%sn/", s); return 0;}int st(char s){ strcpy(s,/"How are you?/"); //改变字符数组内容}
第1次编译给出警告信息,第2次能产生正确结果。如何排除警告信息?
【解答】st函数没有返回值。因为主函数没有使用变量接收函数的返回值,而函数直接修改参数的值,所以只给出警告信息。在st函数增加“return 0;”语句即可排除警告信息。
对于非void类型,即使不使用它的返回值,也必须使用return语句返回一个值。一般返回0值表示正常返回。
其实,本程序不需要返回值,将st函数设计为void类型,即
void st(char s){ strcpy(s,/"How are you?/");}
2.函数使用临时变量作为返回值
【例6.14】试问这个程序正确吗?
#include <stdio.h>int max(int , int );int main(){ int a=33,b=55,c=0,d=100; max(a, b); //6 d=d+c; //7 printf(/"c=%dn/",d ); return 0;}int max(int a, int b){ int x=5,y=8,c; if(a<b) c=b+x; else c=a+y; return c;}
【解答】程序运行正确,但没有意义。程序没有实现任何功能。max使用自己的临时变量c作为返回值,这个变量与主程序的同名变量没有关系。主程序没有接收这个返回值,也没有使用它,max调用结束,返回值也就失去任何意义。
主程序使用它只能有两种方式。一是使用一个同类型的变量接收它的返回值。修改语句
c=max(a,b);
这时“d=d+c;”就有了意义。二是作为printf函数的参数,删除6和7两条语句,使用
printf(/"c=%dn/",d+max(a,b));
输出最终结果。
3.不能使用临时数组名作为返回值
【例6.15】返回值错误的例子。
#include <stdio.h>int *sp( int [ ]);int main( ){ int a[3]={1,3,5},i,*p; for(i=0; i<3; i++) printf(/"%d /", a[i]); printf(/"n/"); p=sp(a); for(i=0; i<3; i++) printf(/"%d /", *(p+i)); printf(/"n/"); return 0;}int *sp(int s){ int b[3]; b[0]=2+s[0]; b[1]=4+s[1]; b[2]=6-s[2]+b[1]; return b;}
数组b是函数sp的临时数组,函数不能返回数组,这里其实是返回数组首地址的指针。虽然使用指针把存储b的首地址返给主函数,但当函数消失后,数组也就不存在了。所以返回的只是一个指向原来存储b的首地址,因为数组b不存在了,当然这个地址的内容也就不可预测了,所以对这个地址的一系列操作,也就无所适从了。
解决的办法是使用static定义数组b,使得返回的指针指向静态数组b。由此可见,并不是使用指针就能保证返回值。被调函数里定义的变量可以作为返回值,但不能使用普通数组。
4.返回临时指针必须是首地址
【例6.16】下面是将例6.15的sp函数改写的程序,找出存在的错误。
int *sp(int s){ int *p; p=(int*)(malloc(3*sizeof(s))); *p++=2+s[0]; *p++=4+s[1]; *p=6-s[2]+*(p-1); p=p-1; return p;}
【解答】程序计算错误。*(p-1)是利用偏移量,没有移动指针的位置,这时的指针是指向第3个元素。返回指针时,一定要保证是分配给指针的首地址。
将“p=p-1;”改为:“p=p-2”即可。
另外,申请内存的数量是sizeof(s)(它计算的是整个数组)。推荐直接使用下标,即
int *sp(int s){ int *p; p=(int*)(malloc(sizeof(s))); p[0]=2+s[0]; p[1]=4+s[1]; p[2]=6-s[2]+p[1]; return p;}
每种数据类型都可定义相应的函数类型和指针函数,并在函数里面使用return语句返回一个或多个返回值,但每次调用只有一个满足返回条件,而且返回值的类型必须与函数类型一致。除非出错时的强行退出,否则均绝无例外。
void不能定义数据类型,但可以定义函数和指针。由于void类型的函数没有返回值,所以常用来输出信息。
如果不允许被调函数修改实参的值,可以使用const限定。