C语言函数

一、函数的概念

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)
作者:码农有道

如果这篇文章对您有帮助,请点赞支持,或在您的博客中转发我的文章,谢谢!!!
如果文章有错别字,或者内容有错误,或其他的建议和意见,请您留言指正,非常感谢!!!

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值