【C语言】函数

        本文将从以下几个方面对函数的知识点进行讲解:1.函数是什么;2.库函数 ;3.自定义函数;4.函数参数;5.函数调用;6.函数的嵌套调用和链式访问;7.函数的声明和定义;8.函数递归

1.函数是什么

        相较于数学中的函数,编程语言中的函数(也称为子程序)作为整个程序中的一个部分,由一个或多个语句块组成,它独立于其它代码,负责某一个功能的实现。一般会有输入参数和返回值,提供对过程的封装和细节的隐藏。

2.库函数

        库函数(Library function)是将函数封装入库,供用户使用的一种方式。方法是把一些常用到的函数编完放到一个文件里,供不同的人进行调用。调用的时候把它所在的文件名用#include<>加到里面就可以了。一般是放到lib文件里的。

        一般是指编译器提供的可在c源程序中调用的函数。可分为两类,一类是c语言标准规定的库函数,一类是编译器特定的库函数。

        由于版权原因,库函数的源代码一般是不可见的,但在头文件中你可以看到它对外的接口库函数简介。

        C语言的语句十分简单,如果要使用C语言的语句直接计算sin或cos函数,就需要编写颇为复杂的程序。因为C语言的语句中没有提供直接计算sin或cos函数的语句。又如为了显示一段文字,我们在C语言中也找不到显示语句,只能使用库函数printf。

        C语言的库函数并不是C语言本身的一部分,它是由编译程序根据一般用户的需要编制并提供用户使用的一组程序。C的库函数极大地方便了用户,同时也补充了C语言本身的不足。事实上,在编写C语言程序时,应当尽可能多地使用库函数,这样既可以提高程序的运行效率,又可以提高编程的质量。

3.自定义函数

        程序员可以自己设定一些自定义函数来解决库函数不能解决的问题,自定义函数也有函数名,返回值类型和函数参数。

          此处我定义了一个名为Max函数来求两个整数的较大值。该函数返回值类型为int,有两个整型参数。

         此处我定义了一个名为Swap1的函数,旨在交换两个变量的值,该函数没有返回值(也可以说是void),有两个整型参数。从结果上来看,该函数没有实现预定功能,因为此处Swap1函数的形参x和y接收到的仅仅是实参a和b的值的临时拷贝,所以x和y在做出改变后,并不能让a和b做出相应的改变。而下面的Swap2函数将能实现预定的交换功能。

      

         此处我定义了一个名为Swap2的函数,旨在交换两个变量的值,该函数没有返回值(也可以说是void),有两个指针类型的参数。从结果上来看,该函数实现了预定功能,因为此处Swap2函数的形参x和y接收到的是实参a和b的地址,所以x和y在做出改变后,可以让a和b做出相应的改变。

4.函数参数

        函数参数分为两类,一类是实际参数,简称实参;另一类是形式参数,简称形参。

4.1实参

        真实传给函数的参数,叫实参。实参可以是:常量,变量,函数和表达式等。无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传给形参。上述main()函数中传递给Swap1的a,b和传递给Swap2的&a,&b都是实参。

4.2形参

        形参是指函数名括号中的变量,因为形参只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形参在函数调用完成之后就自动销毁了,因此形参只在函数调用中有效。

上述Swap1和Swap2的参数x和y都是形参。

5.函数调用

        函数调用分为两类,一类是传值调用,另一类是传址调用。

5.1传值调用

        函数的形参和实参分别占用不同的内存块,形参的改变不影响实参。

5.2传址调用

        传址调用是把函数外部创建变量的内存地址传给函数参数的一种调用函数的方式。

        这种传参方式可以让函数和函数外部的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量       

        注意:1.若要把一个数组传递给一个函数,那么只要使用不带方括号的数组名作为函数实参调用函数即可,不能带方括号和下标。由于数组名代表数组第一个元素的地址,因此数组名作为函数实参实际上是将数组的首地址传给被调函数。将数组的首地址传给被调函数后,形参与实参数组则具有相同的首地址,从而它们占用同一段存储单元,故而被调函数对形参数组的改变会直接影响到实参数组。对于形参中的数组,无需在[ ]中添加数字,因为我们并不是真的在创建一个数组。

                   2.形参和实参的名字可以相同也可以不同,只要相对位置和类型对应上即可。

        以下为四道习题:

6.函数的嵌套调用和链式访问

        函数不可以嵌套定义,即每个函数的定义都应当是同一等级的、相互独立的,但是函数可以嵌套调用。所谓嵌套调用,即函数之间的相互调用,可以在一个函数的内部调用另一个函数来实现某种功能。

        链式访问,即将一个函数的返回值作为另外一个函数的参数,与数学中的复合函数类似。

        printf()函数的返回值是打印纸屏幕上的字符的个数,例题如下:

        最外层的printf调用中间的printf,中间的printf又调用最里面的printf,故而本题需要求出中间的printf和最里面的printf的返回值各是多少。 最外层的printf需要打印中间的printf的返回值,而要求中间的printf的返回值,则先将最里面的printf要打印的值求出来,是43,43是两个字符,故而最里面的printf的返回值为2,2是1个字符,故而中间的printf的返回值为1,故而最外层的printf打印的值为1。明显是最里面的printf先打印,才能出现返回值给中间的printf,接着是打印中间的printf需要打印的值,最后打印最外层的printf需要打印的值,故而最后打印值为4321

        

                 

7.函数的声明和定义

        参考上述3.自定义函数

        由于计算机是按照从上至下的顺序读取代码,所以在调用函数时,若调用函数的语句出现在函数的定义之后,则无需多问;若调用函数的语句在函数的定义之前,则需要进行声明,声明的格式为:在函数的定义后面加上一个分号组成一条语句放在调用函数的语句之前即可(只是调用形参的那一行)。

        

8.函数递归

        递归:程序调用自身的编程技巧称为递归。它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可以描述出解题过程中所需要的多次重复计算,大大地减少了程序的代码量。递归的主要思考方式在于:把大事化小

        递归的两个必要条件:1.存在限制条件,当满足这个限制条件时,递归便不再继续。

                                            2.每次递归调用之后越来越接近这个限制条件

        注意:上述两个条件是必要条件,而不是充要条件。

        下图第一个程序可以正常运行,利用函数的递归完成预定任务,第二个程序虽然满足了上述两个条件,但是并没有完成预定任务,因为出现了Stack overflow(栈溢出)。

 

         具体解析如下:

        在内存中,存在下列三个区域

        名称                                功能

        栈区                                存放局部变量,函数形参

        堆区                                动态内存分配,如:malloc/free,calloc,realloc

        静态区                             存放全局变量,静态变量

        栈的特点是先进后出,后进先出

       注意:1.不能死递归,一定要有跳出条件,每次递归都要逼近跳出条件。

                  2.在写递归代码的时候,递归层次不能太深。

递归与迭代

        深层剖析,递归有点循环的意思,因为它一直在重复做相同的事情,但是它本质上不是循环。而迭代是重复反馈过程的活动,每一次迭代的结果会作为下一次迭代的初始值。

       

        递归是一个树结构,从字面可以其理解为重复“递推”和“回归”的过程,当“递推”到达底部时就会开始“回归”,其过程相当于树的深度优先遍历。

        迭代是一个环结构,从初始状态开始,每次迭代都遍历这个环,并更新状态,多次迭代直到到达结束状态。

上述解释引自:

作者:在彼处
链接:https://www.jianshu.com/p/32bcc45efd32
来源:简书

         运用递归来实现,问题是效率较低,有大量的重复计算。

        此种函数定义的思想是:在x>2时,将变量c指定为要求的斐波那契数,先将其赋值为前两个数,即a与b的和,接着再将第一个数赋值为第二个数b的值,将第二个数b赋值为c,x值减去1,进行下一轮循环。直至x=2时,循环不再继续,进行了x-2次循环,c获得了x-2次赋值(x=3时,需要进行一次前两个数相加的计算,x=4时,需要进行两次前两个数相加的计算......x=n时,需要进行n-2次前两个数的相加计算。)。

        当x=1,2时,斐波那契数为1,直接返回c。

函数递归的经典问题:汉诺塔,青蛙跳台。

本文代码链接为:https://github.com/qigezongdui/C-

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值