您的位置:首页 > 编程语言 > C语言/C++

C语言函数

2020-04-07 12:12 1266 查看

文章目录

  • 二、自定义函数的声明
  • 三、自定义函数的定义
  • 四、自定义函数代码的组织
  • 五、库函数
  • 六、需要包含哪些头文件
  • 七、调用函数的方法
  • 八、函数调用的过程
  • 九、函数参数的传递
  • 十、const约束
  • 十一、应用经验
  • 十二、课后作业
  • 十三、版权声明
  • 一、函数的概念

    1、函数的概念

    每个C程序都至少有一个函数,即main主函数 ,如果程序的任务比较简单,全部的代码都写在main函数中,但是,在实际开发中,程序的任务往往比较复杂,如果全部的代码都写在main函数中,main函数体将非常庞大臃肿,代码重复。

    我们可以把程序的任务分工到不同的子函数中,main更关心业务逻辑和处理流程,需要执行某任务的时候,调用子函数就可以了。

    2、函数的分类

    为了方使理解,我们把函数分为库函数和自定义函数(子函数)。

    库函数是C语言提供的,实现了某些基本的功能,例如scanf、printf,在程序中可以直接使用。

    自定义函数是程序员为了完成某项任务而编写的函数,目的是为了实现某项的功能或让主程序更简洁。自定义函数在使用之前,必须先声明和定义。

    二、自定义函数的声明

    自定义函数的声明包括了返回值函数名参数列表。有些程序员把函数声明说成是函数原型,只是用词不同,意思是一样的。

    C语言中的声明函数的语法如下:

    return_type function_name( parameter list );

    1)返回值的数据类型return_type:函数执行完任务后的返回值,可以是int、char、double或其它自定义的数据类型。如果函数只执行任务而不返回值,return_type用关键字 void表示,如下:

    void function_name( parameter list );

    2)函数名function_name:函数名是标识符,命名规则与变量相同。

    3)参数列表parameter list:当函数被调用时,调用者需要向函数传递参数。参数列表包括参数的数据类型和书写顺序。参数列表是可选的,也就是说,函数可以没有参数,如下:

    return_type function_name();

    函数声明示例:

    // 判断超女身材函数的声明
    // 函数名:checksc
    // 参数:height,身高,单位cm。
    // 返回值:0-不合格;1-娇小;2-标准;3-高挑
    int checksc(int height);

    声明了一个函数,返回值是int类型,函数名是checksc,函数只有一个参数int height,注意,函数的声明语句最后的分号不能少。

    如果把自定义函数比喻成工具,函数的声明就是这个工具的设计图纸。

    三、自定义函数的定义

    自定义函数是工具,如果想让这个工具能被使用,光有设计图纸还不行,还要把工具制造出来,函数的定义就是这个工具的实际主体,是为了实现函数的功能而编写的代码。

    C语言中的函数定义的语法如下:

    return_type function_name( parameter list )       // 注意,不要在函数定义的最后加分号。
    {
    // 实现函数功能的代码
    }

    函数定义的return_type、function_name和parameter list必须与函数声明一致。

    函数主体包含为了完成任务需要执行语句的集合,放在花括号内。

    示例

    // 判断超女身材函数的定义
    int checksc(int height)
    {
    if ( (height>=160) && (height<165) ) return 1;  // 娇小
    if ( (height>=165) && (height<175) ) return 2;  // 标准
    if ( (height>=175) && (height<180) ) return 3;  // 高挑
    
    return 0;   // 不合格
    }

    四、自定义函数代码的组织

    1、非通用能功的函数

    如果自定义函数只在调用者程序中使用,可以在调用者程序中声明和定义,声明一般为调用者程序的上部,定义一般在调用者程序的下部,这并不是C语言的规定,而是为了让程序更方便阅读,程序员约定的写法。

    示例(book45.c)

    /*
    *  程序名:book45.c,此程序演示自定义函数在主程序中声明和定义
    *  作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include <stdio.h>
    #include <string.h>
    
    // 判断超女身材函数的声明
    // 函数名:checksc
    // 参数:height,身高,单位cm。
    // 返回值:0-不合格;1-娇小;2-标准;3-高挑
    int checksc(int height);
    
    int main()
    {
    int ii,jj;
    
    printf("请输入超女的身高(单位:厘米):");
    scanf("%d",&ii);
    
    jj=checksc(ii);   // 调用checksc函数判断身材
    
    if (jj==0) printf("不合格。\n");
    if (jj==1) printf("娇小。\n");
    if (jj==2) printf("标准。\n");
    if (jj==3) printf("高挑。\n");
    }
    
    // 判断超女身材函数的定义
    int checksc(int height)
    {
    if ( (height>=160) && (height<165) ) return 1;  // 娇小
    if ( (height>=165) && (height<175) ) return 2;  // 标准
    if ( (height>=175) && (height<180) ) return 3;  // 高挑
    
    return 0;   // 不合格
    }

    在book45.c中,判断超女身材的函数(checksc)不是公共的功能,只在选秀程序使用,所以它的声明和定义都写在book45.c中。

    2、通用能功的函数

    如果自定义函数是一个通用的功能模块,可以在公共的头文件中声明,在公共的程序文件中定义。

    如果某程序需要调用公共的函数,在调用者程序中用#include指令包含公共的头文件,编译的时候把调用者程序和公共的程序文件一起编译。

    在以下的示例中,函数min和max是公共的函数,在_public.h头文件中声明,在_public.c程序文件中定义,在book46.c程序中被调用。

    1)公共的头文件(_public.h)

    /*
    * 程序名:_public.h,公共功能函数声明的头文件
    * 作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    // 声明min函数,用于比较两个整数的大小,取小者
    int min(const int ii1,const int ii2);
    
    // 声明max函数,用于比较两个整数的大小,取大者
    int max(const int ii1,const int ii2);

    2)公共的程序文件(_public.c)

    /*
    * 程序名:_public.c,公共功能函数声明的程序文件
    * 作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include "_public.h"  // 包含自定义函数声明的头文件
    
    // 用于比较两个整数的大小,函数返回较小者
    int min(const int ii1,const int ii2)   // min函数定义
    {
    if (ii1<ii2) return ii1;
    
    return ii2;
    }
    
    // 用于比较两个整数的大小,函数返回较大者
    int max(const int ii1,const int ii2)   // max函数定义
    {
    if (ii1>ii2) return ii1;
    
    return ii2;
    }

    3)调用者程序文件(book46.c)

    /*
    * 程序名:book46.c,此程序演示了在主程序的外部文件中声明和定义函数
    * 作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include "_public.h"  // 把_public.h头文件包含进来
    
    int main()
    {
    int xx,yy,imin,imax;
    
    xx=50; yy=80;
    
    imin=min(xx,yy);
    imax=max(xx,yy);
    
    printf("imin=%d,imax=%d\n",imin,imax);
    }

    4)编译运行

    3、注意事项

    1)在book46.c的第5行

    #include "_public.h"
    ,这里包含头文件是用双引号,不是尖括号<>,这两者的差别如下:

    #include <>
    用于包含系统提供的头文件,编译的时候,gcc在系统的头文件目录中寻找头文件。

    #include ""
    用于包含程序员自定义的头文件,编译的时候,gcc先在当前目录中寻找头文件,如果找不到,再到系统的头文件目录中寻找。

    2)编译程序的时候,要把调用者程序和公共程序文件一起编译,否则编译器会报错。

    3)C语言对公共函数的头文件(_public.h)和程序文件(_public.c)的命名没有规定,由程序员自己命名,为了增加程序的可读性,尽可能采用一些有意义的文件名。

    五、库函数

    C语言提供了很多标准函数(C standard library),简称库函数,调用这些函数可以完成一些基本的功能,例如printf、scanf、memset、strcpy等。C语言的库函数有几百个,常用的不超过30%,在以后的章节中我将详细介绍常用库函数的应用场景和使用方法。

    C语言标准库函数的声明的头文件存放在/usr/include目录中,如下:

    <asset.h>     <ctype.h>       <errno.h>     <float.h>    <limits.h>
    <locale.h>    <math.h>     <setjmp.h>   <signal.h>     <stdarg.h>
    <stddef.h>   <stdlib.h>   <stdio.h>      <string.h>      <time.h>

    C语言库函数的定义的文件是

    /usr/lib/gcc/x86_64-redhat-linux/4.4.4/libgcc.a
    (不同编译器的版本目录名有所不同),这是一个打包好的库文件,把程序文件打包成库文件的方法以后再详细介绍。

    我们用gcc编译程序的时候并没有把libgcc.a包含进来,那是因为gcc编译器缺省会包含它,但是,程序员自定义函数的程序文件就没有这种待遇,需要手工的包含进来与程序一起编译。

    六、需要包含哪些头文件

    我们在使用库函数的时候,如果不包含它的头文件,编译时会出现警告或错误,如下:


    那么,在我们编写的程序中,应该包含哪些头文件呢?有两种方法,一是上百度上查资料,二是使用Linux系统提供的帮助,以strcpy函数为例,在命令行下输入man strcpy回车,如下:

    man显示了函数的声明的头文件(第5行),函数的参数、使用方法和返回值。

    注意了,如果程序中调用了库函数但没有包含它头文件,编译的时候不一定是警告,也可能是报错,函数无法识别等,这个要看编译器,不同C语言的编译器的处理方式不一样。

    七、调用函数的方法

    库函数是系统提供的工具,自定义函数是程序员自己补充的工具,对使用者来说都一样,没有区别。

    在C语言中,函数的调用非常灵活,可以独占一行语句,也可以当成常量赋值给变量,也可以当成函数的参数。

    如果函数的返回值是void,表示该函数的调用一定会成功,一般用单行书写,独占一条语句。

    如果函数的返回值不是void,可以不关心它的返回值,也可以当成常量用于任何表达式中。

    示例(book47.c)

    /*
    * 程序名:book47.c,此程序演示了函数的灵活调用。
    * 作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include "_public.h"  // 把_public.h头文件包含进来
    
    int main()
    {
    int i=max(30,45);
    
    max(30,20);   // 没有接收返回值,max的活白干了。
    
    55;      // 这是什么鬼?
    
    i=max(min(45,38),50);
    
    i=min(max(min(45,38),50),25);
    
    printf("30和50相比,更大的值是%d。\n",max(30,50));
    }

    大家可能对这个代码不理解,一句话:如果函数的返回值是整数,就可以把函数当成整数来用,如果返回值是小数,就可以把函数当成小数来用,……。

    八、函数调用的过程

    在程序中调用子函数时,程序的流程进入子函数的代码中,当子函数返回时(或到达函数的结束括号时),程序的流程回到调用者程序。

    示例(book48.c)

    /*
    *  程序名:book48.c,此程序演示了函数的调用的过程
    *  作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include <stdio.h>
    #include <string.h>
    
    // 声明func函数,无返回值无参数
    void func();
    
    int main()
    {
    printf("即将调用func函数。\n");
    
    func();
    
    printf("调用func函数已完成。\n");
    
    return 0;
    }
    
    void func()
    {
    int ii=0;
    
    for (ii=0;ii<5;ii++)
    {
    sleep(1);    // sleep是C语言的库函数,睡眠
    printf("已经过去了%d秒。\n",ii+1);
    }
    }

    运行效果

    九、函数参数的传递

    函数的参数可以理解为函数内部的变量,参数传递就是调用者程序把变量(或常量)的值复制一份给函数的参数,简单说来就是复制的过程。一旦完成数据的复制,调用者程序的变量和函数的参数就再也没有瓜葛了,所以,在函数调用的过程中,函数内部变量的值发生改变并不会影响调用者程序的变量的值。

    我们在调用函数的时候,不关心函数参数的名称,函数参数的名称是函数自己的事情,是函数的内部变量,只在函数内部使用,与调用者无关。

    示例(book49.c)

    /*
    * 程序名:book49.c,此程序演示了函数参数的传递
    * 作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include <stdio.h>
    
    void funcld(int b);   // 声明函数funcld,无返回值
    
    int main()
    {
    int a=10;
    
    printf("调用funcld前a的值是%d.\n",a);
    funcld(a);
    printf("调用funcld后a的值是%d.\n",a);
    }
    
    void funcld(int b)
    {
    printf("赋值前b的值是%d.\n",b);
    b=20;
    printf("赋值后b的值是%d.\n",b);
    }

    运行效果

    关于函数的参数,在很多教程中有很多说法,如“形参”、“实参”、“值传递”、“地址传递”等,这些说法把简单的概念复杂化了,大家不必理会。

    十、const约束

    const 是 constant 的缩写,意思是“恒定不变的”,它是定义只读变量的关键字。用 const 定义只读变量的方法很简单,就在定义变量时前面加 const 即可,如:

    const  double  pi = 3.1415926;

    用 const 定义的变量的值是不允许改变的,不允许给它重新赋值,即使是赋相同的值也不可以。所以说它定义的是只读变量。这也就意味着必须在定义的时候就给它赋初值,如果程序中试图改变它的值,编译的时候就会报错。

    在变量前加const约束,主要用于定义函数的参数,表示该参数在函数中是只读取,不允许改变,如果函数中试图改变它的值,编译的时候就会报错。

    例如:

    编译如下:

    为什么要在函数的参数前加const?有两个目的:1)防止程序员犯错,如果程序员犯了错误,编译器就能发现;2)增加了源代码的可读性。在实际开发中,函数的参数不加const不会有任何问题,但是,程序员一般都会为只读变量加上const约束,这是一个好的习惯。

    十一、应用经验

    1、如何寻找函数

    在我的课程中,会介绍常用库函数的使用方法,但也有漏掉的。查资料能力是程序员的基本技能,它可以提升您解决问题的能力。

    例如要查找C语言复制字符串功能的函数,在百度上输入“C语言复制字符串”搜索就可以了,您想查什么就输入什么。

    然后,打开多几个网页看看,基本上能找到答案。

    注意一个问题,网上的内容太多太杂乱,大部分文章是初学者发的博客,重点关注百度百科的文章。

    2、测试函数的功能

    以strcpy函数为例,函数的声明如下。

    char *strcpy(char *dest, const char *src);

    函数功能:字符串复制。

    函数名:strcpy。

    dest参数:目标字符串。

    src参数:待复制的内容,有const约束。

    返回值:返回dest,这是提高函数可用性的常用的处理方法。

    用代码测试一下:

    char strname[50];
    strcpy(strname,"西施");
    printf("=%s=\n",strname);
    printf("=%s=\n",strcpy(strname,"西施"));

    然后,看看输出的结果是不是“=西施=”,用=号夹住输出的内容是为了看清楚有没有其它的字符。

    十二、课后作业

    1)编写示例程序,自定义一个根据超女的胸围判断身材的函数,判断标准由您定,类似book45.c。

    2)C语言的库函数肯定是不够用的,程序员必须要有自己的函数库,从本章节就开始准备,创建您自己的函数库的头文件和程序文件,头文件和程序文件的命名由您定,先放两个函数进去,声明如下,然后写示例程序调用它们。

    // 声明max函数,取两个数值的较大者
    int max(int ii1,int ii2);
    
    // 声明min函数,取两个数值的较小者
    int min(int ii1,int ii2);

    这两个自定义函数的功能虽然简单,但是,千里之行,始于足下,慢慢积累。

    3)本章节的内容非常重要,建议大家看多几遍视频,用程序测试每个知识点,充分的理解它。

    十三、版权声明

    C语言技术网原创文章,转载请说明文章的来源、作者和原文的链接。
    来源:C语言技术网(www.freecplus.net)
    作者:码农有道

    如果文章有错别字,或者内容有错误,或其他的建议和意见,请您留言指正,非常感谢!!!

    • 点赞
    • 收藏
    • 分享
    • 文章举报
    C语言技术网-码农有道 博客专家 发布了203 篇原创文章 · 获赞 507 · 访问量 12万+ 私信 关注
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: