项目八 任务二 函数的进阶

任务二 函数的进阶
任务描述
在上一任务我们已经学习函数的定义以及函数的简单调用,接下来我们将继续来学习函数的进阶部分,其中包括函数的参数的进阶和函数返回值的进阶,学完任务可以对函数的参数和函数的返回值灵活运用。
学习目标
掌握函数的参数的使用。
掌握值传递的方式。
掌握数组作为函数参数的使用。
函数的返回值的概念。
函数返回值的注意细节。
数组作为函数参数的使用。
递归函数的使用。
相关知识
8-2-1 进一步来了解函数的参数
在初步认识函数的时候,我们提到了函数参数,接下来我们来具体讲一下函数的参数,参数有“形式参数”、“实际参数”两个概念,简称是“形参”、“实参”。
函数形参,就是函数定义时函数名后面小括号中的变量。需要注意的是,形参只能是变量。
函数实参,就是调用函数时传入的数据。实参可以是常量、变量、表达式……等。通俗理解:形参是定义函数时候用的;实参是调用函数时候“实际”传递的数据。

接下来我们通过一个案例来给大家解释形参和实参的用法。
实例8- 8 函数形参和实参的用法。

#include<stdio.h>
void fun(int num)    //num 是形参
{
    printf("num是参数,是调用函数传过来的值num=%d\n",num);
}
int main()
{
    int a=5;
    fun(100);     //100 是实参
    fun(a);     // a也是实参
    fun(a+3);   //a+3也是参数
    getchar();
    return 0;
}

运行结果如图 8-9所示。
在这里插入图片描述
图8- 9 实例8-8的运行结果
通过上面的案例我们知道只有定义在方法名()括号里面的被称为形式参数,main函数里面调用的传递的数值是实参。
8-2-2 参数的值传递
上文讲到了函数的实际参数和形式参数,实际参数经过方法调用把值传递给函数,其实在参数传递的过程中,也有两种形式:一种是数据复制方式,另外一种是地址传值方式。
1.传值方式
传值方式又称数据复制方式,它是把实参值本身复制给被调用函数的形参,使形参获得初始值。在传值方式的函数调用中,形式参数必须是变量,而实际参数可以是变量、常量、函数调用和表达式等。
下面我们通过案例来进行讲解
实例8- 9 函数参数的传值方式。

#include<stdio.h>
void fun(int num)    
{
    printf("值传递方式传参数num=%d\n",num);
}
int main()
{
    fun(100);    //实参本身的数值是100
    getchar();
    return 0;
}

结果如图 8-10所示。
在这里插入图片描述

图8- 10 实例8-9的运行结果
为了帮助大家更好地理解执行流程,接下来通过一张图来描述,如图所示8-11所示。
在这里插入图片描述
图8- 11 值传递的流程
2.地址复制方式
地址复制方式又叫传地址方式,它是把地址常量而不是数据传递给被调用函数的形参。这种方式一般以地址常量作实参,如数组名指针(后面讲)等;形参一般是指针变量(后面讲)或数组名。
实例8- 10函数参数的传地址方式。

#include<stdio.h>
void fun1(int num [])    //num 是形参
{
  printf("传递的地址是num=%d\n",num);
  int i;
  printf("传递的地址的获得的数据如下 \n");
  for(i=0;i<3;i++){
   printf("%d\t" ,num[i]);
  }
}
int main()
{
  int arr[]={23,22,12};;
  fun1(arr);    
  getchar();
  return 0;
}

运行结果 如图 8-12所示。
在这里插入图片描述

图8- 12 实例8-10运行结果
为了帮助大家更好地理解执行流程,接下来通过一张图来描述,如图所示8-13所示。
在这里插入图片描述
图8- 13 地址复制的流程
接下来我们做来演示一个参数是地址值的案例,案例如下。
实例8- 11数组a中存放了一个学生5门课程的成绩,求平均成绩。

#include <stdio.h>
 average(float a[5]){
    int i;
    float av,s=a[0];
    for(i=1;i<5;i++)
        s=s+a[i];
    av=s/5;
 printf("平均分是 %.2f",av);
    }
int main(){
    float score[5];
    int i;
    printf("请输入5个数值:\n");
    for(i=0;i<5;i++)
        scanf("%f",&score[i]);
    average(score);
    getchar();
    return 0;
}

运行结果如下 如图8-14所示。
在这里插入图片描述
图8- 14 实例8-11运行结果
本程序首先定义了一个函数average,有一个形参为实型数组a,长度为5。在函数average中,把各元素值相加求出平均值。主函数main 中首先完成数组score的输入,然后以score作为实参调用average函数,最后输出av值也就是平均分。
8-2-3 进一步来了解函数的返回值
函数的返回值是指函数被调用之后,执行函数体中的代码所得到的结果,这个结果通过 return 语句返回。如果函数没有返回值,则返回值类型要声明为void,此时,函数体中的return语句可以省略不写;
return语句的一般形式为:
return 表达式;
或者:
return (表达式);
其中表达式可以是常量、变量、函数引用、数组元素、地址常量和其他形式的表达式等。
例如 return max;其中max是变量,又如 return (100+200);
没有函数返回值时,(表达式)可以省略,而写为:return;
为了让读者更好的学习如何使用return语句,我们来分析一个程序
实例8- 12实现返回给调用函数数据。

#include <stdio.h>
int func(int x, int y)
{
    int sum = x + y;
    return sum;
}
int main(){
    int sum = func(100, 200);
    printf("main函数里的sum值%d",sum);
    getchar();
    return 0;
}

运行结果, 如图8-15所示。
在这里插入图片描述

图8- 15 实例8-12运行结果
接下来通过一个图例来演示func()函数的整个调用过程以及return语句的返回过程,如图8-16所示。
在这里插入图片描述
图8- 16 实例8-12代码执行流程
图示说明:func(int x, int y)函数能够返回求和计算的结果,那么定义的函数int func((int x, int y)
{ return x + y; } 这个时候就把 x + y的值返回 sum=add(x,y) 相当于sum=x+y

使用带返回值的函数应注意哪些细节
细节一. 没有返回值的函数为空类型,用void表示。
例如:

void func(){
    printf("helloc");
}

一旦函数的返回值类型被定义为 void,就不能再接收它的值了。例如,下面的语句是错误的:int a = func();
为了使程序有良好的可读性并减少出错, 凡不要求返回值的函数都应定义为 void 类型。
细节二.return 语句可以有多个,可以出现在函数体的任意位置,但是每次调用函数只能有一个 return 语句被执行,所以只有一个返回值。
例如:返回两个整数中较大的一个

int max(int a, int b){
    if(a > b){
        return a;
    }else{
        return b;
    }
}

如果a>b成立,就执行return a,return b不会执行;如果不成立,就执行return b,return a不会执行。
细节三. 函数一旦遇到 return 语句就立即返回,后面的所有语句都不会被执行到了。从这个角度看,return 语句还有强制结束函数执行的作用。
例如:返回两个整数中较大的一个

int max(int a, int b){
    return (a>b) ? a : b;
    printf("Function is performed\n");
}

printf(“Function is performed\n”)代码就是多余的,永远没有执行的机会。
8-2-4 函数的递归调用
一个函数在它的函数体内调用它自身称为递归调用。这种函数称为递归函数。C语言允许函数的递归调用。在递归调用中,主调函数又是被调函数。执行递归函数将反复调用其自身,每调用一次就进入新的一层。
例如,有函数f如下:

int m(int x){
int y;
z=m(y)return z;
}

注意:在实际开发中一定要其使用,防止程序进入死循环,为了防止递归调用无休止地进行,必须在函数内有终止递归调用的手段。常用的办法是加条件判断,满足某种条件后就不再作递归调用,然后逐层返回。
实例8- 13 接下来通过一个计算自然数之和的案例来学习递归调用:

#include <stdio.h>
int sum(int n)
{  if (n == 1)
   {  
  return 1;   //满足条件,递归结束
}
      int temp = sum(n - 1); //在函数体中调用自身
      return temp + n;
}
int main(){
     int a = sum(5);
    printf("利用递归函数求的和\nsum = %d\n",a);
    getchar();
    return 0;
}

运行结果如图 8-17所示。
在这里插入图片描述

图8- 17 实例8-13运行结果
上述案例中sum()函数的内部调用了自身,这就是函数的递归,整个递归过程在n==1时结束,如果没有终止条件整个函数会不断执行下去,进入无休止运行,程序很快就会内存溢出而终止。执行过程如下图8-18所示。
在这里插入图片描述

图8- 18 实例8-13递归实现的流程

猜你喜欢

转载自blog.csdn.net/qq_27248989/article/details/106130894