c语言的函数总结

一、函数概述

构成C程序的基本单元是函数。函数中包含程序的可执行代码。

每个C程序的入口和出口都位于main函数之中。编写程序时,并不是将所有内容
都放在主函数main中。为了方便规划、组织、编写和调试,一般的做法是将一个程序划分成若干个程序模块,每一个程序模块都完成一部分功能。这样,不同的程序模块可以由不同的人来完成,从而可以提高软件开发的效率。
也就是说,主函数可以调用其他函数,其他函数也可以相互调用。在main函数中调用其他函数,这些函数执行完毕之后又返回到main函数中。通常把这些被调用的函数称为下层函数。函数调用发生时,立即执行被调用的函数,而调用者则进入等待的状态,直到被调用函数执行完毕。函数可以有参数和返回值。

例如,盖一栋楼房,在这项工程中,在工程师的指挥下,有工人搬运盖楼的材料,有建筑工人建造楼房,还有工人在楼房外粉刷涂料。编写程序与盖楼的道理是一样的,主函数就像工程师一样,其功能是控制每一步程序的执行,其中定义的其他函数就好比盖楼中的每一道步骤,分别去完成自己特殊的功能。

在这里插入图片描述

二、函数的定义

在程序中编写函数时,函数的定义是让编译器知道函数的功能。定义的函数包括函数头函数体两部分。

1. 函数头

函数头分为以下3个部分:

  • 返回值类型。返回值可以是某个C数据类型。
  • 函数名。函数名也就是函数的标识符,函数名在程序中必须是唯一的。因 为是标识符,所以函数名也要遵守标识符命名规则。
  • 参数表。参数表可以没有变量也可以有多个变量,在进行函数调用时,实 际参数将被复制到这些变量中。

代码如下(示例):

2. 函数体

函数体包括局部变量的声明函数的可执行代码

所有的C程序都必须有一个main函数。该函数已经由系统声明过了,在程序中只需要定义一下即可。main函数的返回值为整型,可以有两个参数,一个是整数,一个是指向字符数组的指针。虽然在调用时有参数传递给main函数,但是在定义main函数时可以不带任何参数,在前面的所有实例中都可以看到,main函数就没有带任何参数。除了main函数外,其他函数在定义和调用时,参数都必须是匹配的。

程序中从来不会调用main函数,只会在开始运行程序时调用main函数。当main函数结束返回时,系统的结束过程将接收这个返回值。至于启动和结束的过程,程序员不必关心,编译器在编译和链接时会自动提供。不过根据习惯,当程序结束时,应该返回整数值。其他返回值的意义由程序的要求所决定,通常都表示程序非正常终止。

3.函数定义的形式

C语言的库函数在编写程序时是可以直接调用的,如printf输出函数。而自定义函数则必须由用户对其进行定义,在其函数的定义中完成函数特定的功能,这样才能被其他函数调用。
一个函数的定义分为函数头和函数体两个部分。函数定义的语法格式如下:
在这里插入图片描述
定义一个函数的代码如下:

在这里插入图片描述
1. 函数头
函数头用来标志一个函数代码的开始,这是一个函数的入口处。函数头分成返回值类型、函数名和参数列表3个部分。
在上面的代码中,函数头下图所示。
在这里插入图片描述
2. 函数体

函数体位于函数头的下方位置,由一对大括号括起来,大括号决定了函数体的范围。函数要实现的特定功能,都是在函数体部分通过代码语句完成的,最后通过return语句返回实现的结果。在上面的代码中,AddTwoNumber函数的功能是实现两个整数加法,因此定义一个整数用来保存加法的计算结果,之后利用传递进来的参数进行加法操作,并将结果保存在result变量中,最后函数要将所得到的结果进行返回。通过这些语句的操作,实现了函数的特定功能。

现在已经了解到定义一个函数应该使用怎样的语法格式,在定义函数时会有如下几种特殊的情况:

  • 无参函数

无参函数也就是没有参数的函数。无参函数的语法格式如下:
在这里插入图片描述
通过代码来看一下无参函数。例如,使用上面的语法定义一个无参函数,代码如下:
在这里插入图片描述

  • 空函数
  • 顾名思义,空函数就是没有任何内容的函数,也没有什么实际作用。空函数既然没有什么实际功能,那么为什么要存在呢?原因是空函数所处的位置是要放一个函数的,只是这个函数现在还未编好,用这个空函数先占一个位置,以后用一个编好的函数来取代它。

空函数的形式如下:
在这里插入图片描述
例如,定义一个空函数,留出一个位置以后再添加其中的功能:
在这里插入图片描述

4、定义与声明

在程序中编写函数时,要先对函数进行声明,再对函数进行定义。函数的声明是让编译器知道函数的名称、参数、返回值类型等信息。函数的定义是让编译器知道函数的功能。

函数声明的格式由函数返回值类型、函数名、参数列表和分号4部分组成,其形式如下:

返回值类型 函数名(参数列表);

此处要注意的是,在声明的最后要用分号“;”作为语句的结尾。例如,声明一个函数的代码如下:

Int ShowNumber(int iNumber);

如果将函数的定义放在调用函数之前,就不需要进行函数的声明,此时函数的定义就包含了函数的声明。

在函数的函数体中常会看到这样一句代码:

return 0;

这就是返回语句。返回语句有以下两个主要用途:

  • 利用返回语句能立即从所在的函数中退出,即返回到调用的程序中去。
  • 返回语句能返回值,即将函数值赋给调用的表达式中。当然,有些函数也 可以没有返回值,例如,返回值类型为void的函数就没有返回值。

说明:

  • (1)函数的返回值都通过函数中的return语句获得,return语句将被调用函
    数中的一个确定值返回到调用函数中。例如,上面代码中Minus自定义函数的最后,
    使用return语句将计算的结果返回到主函数main调用的位置。

return语句后面的括号是可以省略的,例如return 0和return(0)是相同的。

  • (2)函数返回值的类型。既然函数有返回值,这个值当然应该属于某一种确定 的类型,因此应当在定义函数时明确指出函数返回值的类型。

例如:

int Max(int iNum1,int iNum2); double Min(double dNum1,double
dNum2); char Show(char cChar);
  • (3)如果函数值的类型和return语句中表达式的值不一致,则以函数返回值
    的类型为准。数值型数据可以自动进行类型转换,即函数定义的返回值类型决定最 终返回值的类型。

三、函数参数

在调用函数时,大多数情况下,主调函数和被调用函数之间有数据传递关系,这就是前面提到的有参数的函数形式。函数参数的作用是传递数据给函数使用,函数利用接收到的数据进行具体的操作处理。

函数参数在定义函数时放在函数名称的后面,如下图所示。
在这里插入图片描述

1、形式参数与实际参数

在使用函数时,经常会用到形式参数实际参数。两者都叫作参数,那么二者有什么关系?二者之间的区别是什么?两种参数分别起到什么作用?接下来通过形式参数与实际参数的名称和作用来进行理解,再通过一个比喻和实例进行深入理解。

  • (1) 通过名称理解

**形式参数:**顾名思义,就是形式上存在的参数。
**实际参数:**即实际存在的参数。

  • (2). 通过作用理解

**形式参数:**在定义函数时,函数名后面括号中的变量名称为“形式参数”。在函数调用之前,传递给函数的值将被复制到这些形式参数中。
实际参数:在调用一个函数时,也就是真正使用一个函数时,函数名后面括号中的参数为“实际参数”。函数的调用者提供给函数的参数叫实际参数。实际参数是表达式计算的结果,并且被复制给函数的形式参数。

  • (3) 通过一个比喻来理解形式参数和实际参数

母亲拿来了一袋牛奶,将牛奶倒入一个空奶瓶中,然后喂宝宝喝牛奶。函数的作用就相当于宝宝用奶瓶喝牛奶这个动作,实参相当于母亲拿来的一袋牛奶,而空的奶瓶就相当于形参。牛奶放入奶瓶这个动作相当于将实参传递给形参,使用灌好牛奶的奶瓶就相当于函数使用参数进行操作的过程。
在这里插入图片描述

2、数组作函数参数

当数组作为函数的实参时,只传递数组的地址,而不是将整个数组赋值到函数中。当用数组名作为实参调用函数时,指向该数组的第一个元素的指针就被传递到函数中。

  • (1) 数组元素作为函数参数

由于实参可以是表达式形式,数组元素可以是表达式的组成部分,因此数组元素可以作为函数的实参,与用变量作为函数实参一样,是单向传递

  • (2) 数组名作为函数参数

可以用数组名作为函数参数,此时实参与形参都应使用数组名。

  • (3) 可变长度数组作为函数参数
    可以将函数的参数声明成长度可变的数组,在此基础上利用上面的程序进行修改。声明方式的代码如下:
    在这里插入图片描述
    从上面的代码中可以看到,在定义和声明一个函数时将数组作为函数参数,并且没有指明数组此时的大小,这样就将函数参数声明为数组长度可变的数组。
#include<stdio.h>

void Fuzhi(int ivalue[],int num)              /*赋值数组函数*/
{
        int i;
        for(i=0;i<num;i++)
        {
                printf("input data:");
                scanf("%d",&ivalue[i]);
        }
}

void vPrint(int ivalue[],int cnt)                /*打印数组函数*/
{
        int i;
        for(i=0;i<cnt;i++)
        {
                printf("%d\t",ivalue[i]);
        }
}
int main()
{
        int inum = 0;                   /*定义数组大小变量inum*/

        printf("please input what's number:\n");
        scanf("%d",&inum);

        int array[inum];              /*定义数组array*/

        Fuzhi(array,inum);           /*传参*/
        vPrint(array,inum);          
        putchar('\n');

        return 0;
}


输出结果:
在这里插入图片描述

  • (4)使用指针作为函数参数

最后一种方式是将函数参数声明为一个指针。在前面的介绍中也曾提到,当数组作为函数的实参时,只传递数组的地址,而不是将整个数组赋值到函数中去。当用数组名作为实参调用函数时,指向该数组的第一个元素的指针就会被传递到函数中。

例如,声明一个函数参数为指针时,传递数组的方法如下:
在这里插入图片描述
从上面的代码中可以看到,指针在声明Function时作为函数参数。在调用函数时,可以将数组名作为函数的实参进行传递。

把上面的代码改为用指针实现:

#include<stdio.h>

void Fuzhi(int* ivalue,int num)
{
        int i;
        for(i=0;i<num;i++)
        {
                printf("input data:");
                scanf("%d",ivalue++);
        }


}

void vPrint(int* ivalue,int cnt)
{
        int i;
        for(i=0;i<cnt;i++)
        {
                printf("%d\t",*ivalue++);
        }


}
int main()
{
        int inum = 0;

        printf("please input what's number:\n");
        scanf("%d",&inum);

        int array[inum];

        Fuzhi(array,inum);
        vPrint(array,inum);
        putchar('\n');

        return 0;
}

输出结果:
在这里插入图片描述

3、main函数的参数

在运行程序时,有时需要将必要的参数传递给主函数。主函数main的形式参数如下:

main(int argc, char* argv[])

两个特殊的内部形参argc和argv是用来接收命令行实参的,这是只有主函数main才具有的参数。

  • argc参数保存命令行的参数个数,是整型变量。这个参数的值至少是1,因为至少程序名就是第一个实参。
  • argv参数是一个指向字符指针数组的指针,这个数组中的每一个元素都指
    向命令行实参。所有命令行实参都是字符串,任何数字都必须由程序转变成为适当 的格式。
#include<stdio.h>

int main(int argc,char *argv[])
{
     	printf("有%d个参数\n",argc);
        printf("%s\n",argv[0]);
        return 0;
}
~    

输出结果:
在这里插入图片描述

四、函数的调用

在生活中,为了能完成某项特殊的工作,需要使用特定功能的工具。首先要去制作这个工具,工具制作完成后,就要进行使用。函数就像要完成某项功能的工具,而使用函数的过程就是函数的调用。

1、函数的调用方式**

一种工具不只有一种使用方式,函数的调用也是如此。函数的调用方式有3种,包括函数语句调用、函数表达式调用和函数参数调用。下面对这3种情况进行介绍。

  • (1)函数语句调用把函数的调用作为一个语句就称为函数语句调用。函数语句调用是最常用的函 数调用方式,如下所示:
    在这里插入图片描述
    这个函数的功能是在函数的内部显示一条消息,这时不要求函数带返回值,只要求完成一定的操作。
  • (2) 函数表达式调用

函数出现在一个表达式中,这时要求函数必须带回一个确定的值,而这个值则作为参加表达式运算的一部分。如下述代码所示:
在这里插入图片描述

  • (3) 函数参数调用

函数调用作为一个函数的实参,也就是将函数返回值作为实参,传递到函数中使用。
函数出现在一个表达式中,这时要求函数带回一个确定的值,这个值用于参加表达式的运算。如下代码所示:
在这里插入图片描述
在这条语句中,AddTwoNum函数的功能还是进行两个数相加,然后将相加的结果作为函数的参数,继续进行计算。

2、 嵌套调用

在C语言中,函数的定义都是互相平行、独立的。也就是说,在定义函数时,一个函数体内不能包含定义的另一个函数,这一点和Pascal语言是不同的(Pascal允许在定义一个函数时,在其函数体内包含另一个函数的定义,而这种形式称为嵌套定义)。例如,下面的代码是错误的:
在这里插入图片描述
从上面的代码中可以看到,在主函数main中定义了一个Display函数,目的是输出一句提示。但C语言是不允许进行嵌套定义的,因此进行编译时就会出现如图所示的错误提示。
在这里插入图片描述
虽然C语言不允许进行嵌套定义,但是可以嵌套调用函数,也就是说,在一个函数体内可以调用另外一个函数。例如,使用下面代码进行函数的嵌套调用:
在这里插入图片描述

用一个比喻来理解。某公司的CEO决定该公司要完成某个目标,但是要完成这个目标就需要将其讲给公司的经理们听,公司的经理们再将要做的内容传递给下级的副经理们听,副经理再讲给下属的职员听,职员按照上级的指示进行工作,最终完成目标,其过程如图所示。
在这里插入图片描述

  • 4
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秃秃秃秃哇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值