C语言函数详解(入门到进阶)

Posted 攻城狮白玉

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言函数详解(入门到进阶)相关的知识,希望对你有一定的参考价值。

目录

前言

一、什么是函数

二、函数的构成

三、函数的调用和声明

四、函数的参数

五、函数的递归

总结

写在后面


前言

最近帮家里的小朋友整理一些学习C语言的知识点

有整体入门基础文章——【C语言】拯救新手,半小时从零到一认识C语言基础

C语言数据类型的详解——【C语言】数据类型一文详解

变量和赋值的详解——【C语言】变量及赋值

指针和数组关系——【C语言】小妹不懂指针和数组的关系?那就安排指针数组关系详解

问了小妹她C语言还有哪些不懂得,提到了函数的应用,那么就安排函数的详解。

一、什么是函数

函数是由一系列语句组合而成的,是一组语句的封装。函数的使用可以让我们避免重复的代码编写,让我们的程序更加的模块化。

其实,咱们从接触C语言开始的时候,就已经接触了函数了。每个C语言程序至少会有一个函数,那就是main()函数。main()函数是C语言程序的入口。除了main()函数,咱们在输出的控制台信息的时候用到的printf()也是一个函数。

函数还有很多叫法,比如方法、子例程或程序,等等。

二、函数的构成

函数是由函数类型,函数名,形参列表,函数主体这几部分构成的。

函数类型 函数名(形参列表){

        函数主体;

}

  • 函数类型,决定了函数最后return的返回值类型,比如是int型函数,那么在函数体里面要用return返回int型的值,如果是char型函数,则返回char型的值。如果不需要返回值的话,则函数类型写为void
  • 函数名,是我们在调用函数时使用的,就跟变量名一个道理
  • 参数列表,咱们在调用函数时,往函数里面传入的参数,这里的参数是可有可无的,写在函数定义的参数列表的参数叫做形式参数(形参),当我们调用函数的时候,填入的叫实际参数(实参)
  • 函数主体,用花括弧{}括起来的,包含所有组成函数的语句。如果函数不是void型的,则函数主体里面要有return语句返回对应类型的值

三、函数的调用和声明

函数的调用方式:

函数名(实参列表);

这里的实参列表,可以是变量(包括普通变量和指针变量),常量,表达式,函数等。实参列表里多个实参之间用逗号【,】来隔开。当定义函数时没有形参列表,则在调用函数的时候也不用传入实参。

在咱们最熟悉的输出语句printf()就是函数的调用,例如

char str[] = "Hello Baiyu";
printf("%s\\n",str);//调用printf()函数,里面的"%s\\n",str就是实际参数
  • “%s\\n”这个是常量
  • str这个是字符串变量

下面用代码演示一下函数的定义、以及几种函数的调用形式:

#include<stdio.h>

//此处定义一个比较两个数取最大值函数
int max(int x, int y) {
    if (x > y) {
        return x;
    }
    else {
        return y;
    }
}
 
 //定义一个无返回值类型的函数,用于调用max()函数输出最大值 
void output(){
    int i_baiyu = 10;
    int i_zhh = 20;

    // 函数作为表达式的一部分
    int i_max = max(i_baiyu, i_zhh);
    int i_max2 = max(i_zhh, i_baiyu) + 100;
    
    // 函数作为自身函数的实参,同时函数也作为表达式的一部分
    int i_max3 = max(max(i_zhh, i_baiyu), i_max2);

    // 函数作为一个单独语句
    printf("i_max的值为:%d\\n", i_max);
    printf("i_max3的值为:%d\\n", i_max3);

    //函数作为调用另一个函数时的实参
    printf("函数作为调用另一个函数时的实参:%d\\n", max(max(i_zhh, i_baiyu), i_max2));
} 
 

//主函数
int main() {
    output();
    return 0;
}

由于C语言代码是从上往下依次执行的,所以对于函数的调用,咱们有两种方式

  1. 函数定义在函数调用之前,函数可以直接调用。
  2. 函数定义在函数调用之后,则需要在函数调用之前先声明被调用的函数之后再调用。

上面这两句话可能看起来有点绕。不能理解,那我们把上面这个比较大小的代码稍微调整一下,把函数定义放在main()函数后面

#include<stdio.h>

//主函数
int main() {
    output();
    return 0;
}
 
 //输出最大值 
void output(){
    int i_baiyu = 10;
    int i_zhh = 20;

    // 函数作为表达式的一部分
    int i_max = max(i_baiyu, i_zhh);
    int i_max2 = max(i_zhh, i_baiyu) + 100;
    
    // 函数作为自身函数的实参,同时函数也作为表达式的一部分
    int i_max3 = max(max(i_zhh, i_baiyu), i_max2);

    // 函数作为一个单独语句
    printf("i_max的值为:%d\\n", i_max);
    printf("i_max3的值为:%d\\n", i_max3);

    //函数作为调用另一个函数时的实参
    printf("函数作为调用另一个函数时的实参:%d\\n", max(max(i_zhh, i_baiyu), i_max2));
} 
 
//此处定义一个比较两个数取最大值函数
int max(int x, int y) {
    if (x > y) {
        return x;
    }
    else {
        return y;
    }
}

这个时候,我们执行程序可能会发现其编译时会有告警,这是因为我们的函数定义放在了函数调用之后。函数在调用的时候找不到函数的定义。

因此,我们只需要在函数调用之前,对函数进行声明,这样子的话,函数定义就可以放在程序的任意位置了。

函数的声明格式如下:

函数类型 函数名(形参列表);

我们发现,函数声明跟函数定义差不多,只是把函数定义时的函数体去掉。

修改后的代码如下:

#include<stdio.h>
void output(); //这里增加output函数的声明
int max(int x, int y);//这里增加max函数的声明

//主函数
int main() {
    output();
    return 0;
}
 
 //输出最大值 
void output(){
    int i_baiyu = 10;
    int i_zhh = 20;

    // 函数作为表达式的一部分
    int i_max = max(i_baiyu, i_zhh);
    int i_max2 = max(i_zhh, i_baiyu) + 100;
    
    // 函数作为自身函数的实参,同时函数也作为表达式的一部分
    int i_max3 = max(max(i_zhh, i_baiyu), i_max2);

    // 函数作为一个单独语句
    printf("i_max的值为:%d\\n", i_max);
    printf("i_max3的值为:%d\\n", i_max3);

    //函数作为调用另一个函数时的实参
    printf("函数作为调用另一个函数时的实参:%d\\n", max(max(i_zhh, i_baiyu), i_max2));
} 
 
//此处定义一个比较两个数取最大值函数
int max(int x, int y) {
    if (x > y) {
        return x;
    }
    else {
        return y;
    }
}

四、函数的参数

前面咱们说过,函数的形式参数列表,可以是变量(包括普通变量指针变量),常量,表达式,函数等。实参列表里多个实参之间用逗号【,】来隔开

这里单独要再强调一下,就是形参就像是函数内其他的局部变量一样。在函数调用结束之后,会进行销毁。我们在向函数传递变量时,会有两种传递参数形式。这也是为啥前面我在变量那里会强调指出有普通变量跟指针变量

  1. 传值调用:该方法会把实际参数的值复制到函数的形式参数,此时,修改函数内形式参数的值并不会影响实际参数的值
  2. 引用调用:通过指针变量来传递,形参会指向实参地址的指针,当对形参指向的值进行操作时,就相当于对实参本身进行操作

上面这样子讲可能不太好理解,还是上代码

这里咱们举一个例子就是来写一个函数,用于交换两个变量的值。

#include <stdio.h>
// 通过普通变量,进行值传递
void swap(int x, int y) {
    printf("交换前x的值为:%d,y的值为:%d\\n", x, y);
    int temp = x;
    x = y;
    y = temp;
    printf("交换后x的值为:%d,y的值为:%d\\n", x, y);
}
// 通过指针变量,进行引用传递
void swap_p(int* x, int* y) {
    printf("交换前x的值为:%d,y的值为:%d\\n", *x, *y);
    int temp = *x;
    *x = *y;
    *y = temp;
    printf("交换后x的值为:%d,y的值为:%d\\n", *x, *y);

}

int main() {
    int i_baiyu = 66;
    int i_zhh = 77;
    printf("swap交换前i_baiyu的值为:%d,i_zhh的值为:%d\\n", i_baiyu,i_zhh);
    swap(i_baiyu, i_zhh);
    printf("swap交换后i_baiyu的值为:%d,i_zhh的值为:%d\\n", i_baiyu,i_zhh);
    printf("-------------------------------------------\\n");
    printf("swap_p交换前i_baiyu的值为:%d,i_zhh的值为:%d\\n", i_baiyu, i_zhh);
    swap_p(&i_baiyu, &i_zhh);
    printf("swap_p交换后i_baiyu的值为:%d,i_zhh的值为:%d\\n", i_baiyu, i_zhh);
    return 0;
}

五、函数的递归

在开始讲函数的递归之前,给大家将一个耳熟能详的故事

从前有座山,山里有座庙,庙里有个老和尚给一个小和尚讲故事,讲什么呢?老和尚说

从前有座山,山里有座庙,庙里有个老和尚给一个小和尚讲故事,讲什么呢?老和尚说

从前有座山,山里有座庙,庙里有个老和尚给一个小和尚讲故事,讲什么呢?老和尚说

......

在C语言中,当函数直接或者间接调用函数本身,就叫做函数的递归。

在使用函数递归的时候,我们要注意设置好一个从函数退出的条件,否则就会进入一个死循环,就像老和尚给小和尚讲故事一样,是无限循环的。

函数的递归,这样子讲可能不太容易懂,下面举几个例子,让大家一起熟悉一下

通过递归求n的阶乘

我们从数学公式可知

n! = n *(n-1)!

#include <stdio.h>

double factorial(unsigned int i)
{
    if (i <= 1)//这里就是结束递归的判断条件
    {
        return 1;
    }
    return i * factorial(i - 1);
}
int  main()
{
    int i_baiyu = 6;// 这里我们计算6的阶乘。
    printf("%d 的阶乘为 %f\\n", i_baiyu, factorial(i_baiyu));
    return 0;
}

 6!= 6 * 5 * 4 * 3 * 2 * 1 = 720

总结

本文讲述了C语言函数的定义、基本使用,和函数的递归。从零到一带各位同学熟悉C语言中函数的使用。

写在后面

如果觉得有用的话,麻烦动动各位发财的小手指,给个一键三连支持一下攻城狮白玉并把本文分享给更多的小伙伴。你的简单支持,我的无限创作动力

如果有想看的内容,也可以在博文底部评论,我会整理出来给到大家~

以上是关于C语言函数详解(入门到进阶)的主要内容,如果未能解决你的问题,请参考以下文章

C语言学习 从入门到进阶

C语言学习 从入门到进阶

C语言学习 从入门到进阶

《C语言深度剖析》第三章 预处理详解 p2(完结) C语言从入门到入土(进阶篇)

C语言学习 从入门到进阶

C语言学习 从入门到进阶