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

《C语言解惑》6.7 函数的返回值

关灯直达底部

设计函数一定要明确函数的返回值,只有明确返回值才能确定函数的类型。函数返回值和参数是两回事。参数是指函数参数表中的变量,这个变量视传递方式而变。传数值不改变参数的值,而传地址值是改变参数值的必要条件,但是否改变,则视使用方法而定。函数返回值是指被调用函数结束时所返回的值,非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限定。