C语言函数

本文详细介绍了C语言中的函数概念,包括函数的分类(库函数与自定义函数),参数(实参、形参及其关系)、函数调用(传值调用和传址调用)、函数嵌套和链式访问,以及递归的含义、必要条件和与迭代的区别。同时提到了递归在解决特定问题(如斐波那契数列)中的应用和注意事项。
摘要由CSDN通过智能技术生成

1. 函数是什么?

 在数学中我们就学过函数,都是你了解C语言中的函数码?维基百科对函数的定义:子程序。

简单来说,一个函数就是一个大型工程中的某部分代码,由一个或多个语句块组成,它负责完成某项特定任务,而且相对于其他代码,具有相对的独立性。

2. 函数的分类

函数可以分为库函数和自定义函数。

2.1 库函数

在使用C语言的过程中,有一些我们会频繁用到的功能,比如求字符串的长度,比如数学中的求开平方等等,为了简化代码,更方便软件开发,于是就有了库函数。我们可以在www.cplusplus,com网站中的C library中去了解到选择C语言有哪些库,库里面的库函数以及如何使用这些库函数。

C语言中常用的库函数都有:

IO函数

字符串操作函数

字符操作函数

内存操作函数

时间/时间函数

数学函数

其他函数

举例:memset函数

memset的语法结构是:void* memset (void* ptr , int value , size_t num)

这个函数的作用是把从ptr开始的num个字节的内容全部设置成特定的值value,value不一定是int类型的值,也可以是字符等其他类型的值。这个函数常用来替换字符串中的某一个字符。

 

在上面的代码中,我们使用memset将str的第三个字符开始的三个字符替换成了字符v。

2.2 自定义函数

库函数虽然提供了我们常用的功能,但是在写程序的时候更重要的还是自定义函数,这是由我们程序员自己创建的函数,自定义函数也有函数名、返回类型、函数参数等,最重要的时函数体,因为函数体的代码才是我们函数功能的实现。

3.函数的参数

3.1 实参

实参时真实传给函数的参数,可以是常量、变量、表达式、函数等,无论实参是何种类型的值,在函数调用的时候都必须有确定的值,以便把这些值传递给形参。

3.2 形参

形式参数是指函数定义中函数名后面的括号里的变量。形式参数只有在函数被调用的时候才实例化(开辟内存),而且形式参数在函数调用完毕后会自动销毁,因此形参只在函数范围内有效。

3.3 形参和实参的关系

当实参传递给形参的时候。形参是实参的一份临时拷贝,对形参的修改不影响实参。

形参和实参的名字可以相同也可以不同。

当需要修改参数时,需要传它的的地址,如果不用修改实参就传值。

数组传参是传数组名,不用加后面的方括号,数组传参本质上传过去的是数组首元素的的地址,而不是将整个数组都传过去,这样会函数会开辟很大的栈帧,浪费空间,所以形参中实际存的是一个指针变量,这就意味着在函数内部去使用sizeof(arr)/sizeof(arr[0])计算数组长度是不靠谱的。对于数组传参,我们只需要传数组名和数组长度就能访问到数组里所有的元素。

4. 函数调用

4.1 传值调用

把实参的值作为参数传给函数。这时候形参只是实参的一份临时拷贝,对形参的修改不会影响实参。

4.2传址调用

传址调用就是把函数外部创建的变量的内存地址传递给函数,这种传参方式可以让函数和函数外部的变量建立起真正的联系,也就是在函数内部可以直接操作函数外部的变量。

注意:函数中执行完return就调用完函数了,会直接返回在主函数,不再执行后面的代码。

           函数功能要尽量单一,不要将多个功能写在一个函数内,要追求高内聚低耦合。

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

5.1 嵌套调用

函数之间是可以相互调用的,这就是嵌套调用,但是不能嵌套定义,就是不能在一个函数内区定义另外一个函数

5.2 链式访问

就是把一个函数的返回值作为另一个函数的参数,链式访问的前提条件是有返回值。

6.函数的声明和定义

6.1 函数声明

返回类型  函数名 (函数参数);

函数的声明就是告诉编译器有一个函数叫什么,参数是什么,返回类型是什么,但是具体存不存在函数声明决定不了,有时候会出现假声明的情况,即声明了,但是没有函数的具体实现(定义)。

函数的声明一般出现在函数使用之前,要满足先声明后使用。如果函数定义在main函数后面,程序运行的时候会按顺序扫描,当扫描到该函数时,因为前面没有出现这个函数的声明或定义,这时候编译器没有见过这个函数,所以会报一个警告。但是当我们把函数定义在main之前则不需要声明也能正常运行。

函数的声明一般放在头文件中,因为我们一般会把不同的模块放在不同的文件中,当包含放有函数声明的头文件时,会把头文件的内容拷贝过来,也就对函数进行了声明。

初学编程是可能会觉得把所有的代码写到一个文件中最方便,那是因为现阶段我们写的代码量很少,但是当我们写的工程代码量很大时,或者在公司里协作工作的时候,模块化设计不仅会让效率变高,而且把不同的功能按模块划分出来更有利于代码的阅读和维护。

6.2 函数的定义

函数的定义主要是指函数的实现,在这里交待了函数是如何实现我们想要实现的功能的。

7.函数递归

7.1 函数递归的含义

简单来说,函数递归就是函数自己调用自己,核心思想是把大事化小。递归可以大大减少函数的代码量。就拿这个问题举例:按顺序打印一个整数的每一位,比如1234.

这时候我们可能会无从下手,但是我们很了解另一个功能:打印一个整数的个位,这个时候我们只需要打印1234%10就可以实现。按照这个思路,我们假设我们写的函数是print(1234),这个函数的功能是打印整数的各位,这时候我们是不是可以想到可以先执行print(123)再来打印我们的

4...

                              

通过上面的代码,我们就递归实现了打印整数的每一位。

7.2 函数递归的必要条件

函数递归的必要条件:

递归使用一定要有限制条件,当满足这个条件时递归便不再继续。没有限制条件的递归就是死递归。每一次函数调用都会在栈区申请空间,死递归会导致栈溢出最终程序崩溃。

每一次递归之后都要越来越接近限制条件。

要记住,递归既要递推,也要回归,而回归的条件就是限制条件,没有回归的递归是死递归。

7.3 递归与迭代

迭代的意思就是重复用,比如循环这种,循环是一种迭代,迭代却不只有循环。

对于有些问题,既可以用递归实现,也可以用迭代实现,一些问题适合用递归完成,比如上面的打印整数的每一位,而有些问题则适合迭代实现,比如求第n个斐波那契数,这个问题如果用递归的话会存在大量重复的计算,花费时间很多,效率太低,时间复杂度为2^n,而用迭代的话循环n次就可以得出结果。

递归不能四递归,且当递归层次太深的时候也会出现栈溢出的情况

递归实现求第n个斐波那契数

迭代实现第n个斐波那契数

关于递归还有几个经典问题,比如汉诺塔和青蛙跳台阶问题,这两个问题后期也会发文来说说解题思路。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值