资讯专栏INFORMATION COLUMN

最强函数学习之路

_Dreams / 3251人阅读

摘要:无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。形式参数当函数调用完成之后就自动销毁了。函数的声明一般出现在函数的使用之前。函数的声明一般要放在头文件中的。

索引

一. 函数是什么
二. 库函数
三. 自定义函数  函数参数
四 函数的嵌套调用和链式访问
五.函数的声明和定义
六.函数递归
一.函数是什么?
对于我们大部分人而言我们最先是在数学中接触函数,eg:f(x) = x+1;
或者更为复杂,我们只需要代入一个x的值,然后按照函数给的模板算就可以了,
其实在c语言中,我们可以类比数学中的函数,只不过这个时候我们只需要输入很少的参数,
然后编译过程是编译器实现的,但函数的实现过程也是我们创造的。
维基百科中对函数的定义: 子程序
在计算机科学中,子程序(英语:Subroutine, procedure, function, routine, method,
subprogram, callable unit),是一个大型程序中的某部分代码, 由一个或多个语句块组
成。它负责完成某项特定任务,而且相较于其他代 码,具备相对的独立性。
一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软
件库。
上述只是很简单的大致概括了一下函数,下面我将会进一步解释函数
   
C语言中函数分为两类:库函数和自定义函数
           
二.库函数
先思考一下问题,什么是库函数?为什么要有库函数?
1. 我们知道在我们学习 C 语言编程的时候,总是在一个代码编写完成之后迫不及待的想知道结果,想
把这个结果打印到我们的屏幕上看看。这个时候我们会频繁的使用一个功能:将信息按照一定的格
式打印到屏幕上( printf )。
2. 在编程的过程中我们会频繁的做一些字符串的拷贝工作( strcpy )。
3. 在编程是我们也计算,总是会计算 n k 次方这样的运算( pow )。
像上面我们描述的基础功能,它们不是业务性的代码。我们在开发的过程中每个程序员都可能用的到,
为了支持可移植性和提高程序的效率,所以 C 语言的基础库中提供了一系列类似的库函数,方便程序员
进行软件开发。
我们平时使用过程中直接一个printf表示打印到屏幕上,实际上实现这个过程要极其复杂的函数,下面是vs上面实现printf功能的部分截图

想一下,如果没有库函数,那么每个程序员的printf实现都是不一样的 ,那么平台的可移植性就等于0,因此,对于经常用到的某些函数功能,在C语言基础库中添加了这些功能实现的函数,因此被叫做库函数,大家都可以用。
那么问题来了,库函数该如何学习呢?
这边介绍一个网站      www.cplusplus.com
这是一个外国网站 做的还是比较好的  strcpy 这个函数我们现在尝试在这个网站上学习这个函数

 我输入strcpy后

在前面加一个头文件,不然无法使用strcpy
#include#includeint main() {	char arr2[] = "zhangdashuai";	char arr1[30];	char arr[40];	strcpy(arr1, arr2);	strcpy(arr, "zhangdasa");	printf("%s/n%s", arr1, arr);	return 0;}

 如果有小伙伴英文是在看不懂,这边还有一个中文版的网站

http://zh.cppreference.com (中文版)
注:
但是库函数必须知道的一个秘密就是:使用库函数,必须包含 #include 对应的头文件。
这里对照文档来学习上面几个库函数,目的是掌握库函数的使用方法。
.   自定义函数
如果库函数能干所有的事情,那还要程序员干什么?
所有更加重要的是 自定义函数
自定义函数和库函数一样,有函数名,返回值类型和函数参数。
但是不一样的是这些都是我们自己来设计。这给程序员一个很大的发挥空间。
函数的组成:
ret_type fun_name ( para1 , * )
{
statement ; // 语句项
}
ret_type 返回类型
fun_name 函数名
para1     函数参数
首先,思考一下,每个函数都必须要有返回值吗?
不一定,如果返回类型是void就不用有返回值,



void

void declarator

When used as a function return type, the void keyword specifies that the function does not return a value

但是其他的如果函数返回类型是int  float 类型的 ,那么在最后就必须加上return 相应的类型数字。

eg:这个menu函数只是为了打印出我想要的菜单,不需要返回某个值

void menu () {	printf("###################");	printf("####1.play#########");	printf("####0.noplay#######");	printf("###################");}
返回值:
一个加法函数
#includeint Add(int x, int y) {	return x + y;}int main() {	int a = 8;	int b = 9;	int c = Add(a, b);	printf("%d/n", c);	return 0;}

函数名的话,就是根据我们想要函数实现的功能,大致翻译成英文即可。

参数,接下来我通过一个代码例子阐述参数的概念——

我现在想创造一个函数,它可以把我穿进去的数字互换一下,,假设我穿进去a=10,b=20,

那么作用使得a=20,b=10;

上代码

#includevoid swap(int x, int y) {	int tam = x;	x = y;	y = tam;}int main() {	int a = 10;	int b = 20;	printf("a=%d b=%d/n", a, b);	swap(a, b);	printf("a=%d b=%d/n", a, b);	return 0;}

???

函数好像跟根本没起作用,为什么???

我们要养成一个好习惯,拒绝伸手党,去vs调试一下

 我们可以看到,虽然x,y的值跟a,b相等

但是发现他们的地址根本不一样???

为什么?

引入参数的概念

  实际参数(实参):
真实传给函数的参数,叫实参。
实参可以是:常量、变量、表达式、函数等。
无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形
参。
  形式参数(形参):
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内
存单
元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有
效。

我们的a,b是实参,x,y是形参,我们通过形参想改变实参的关系,结果证明我们光传递值是不可以的,因为传入实参后,形参还会开辟一个新的空间,我是这样理解的

形参实例化之后其实相当于实参的一份临时拷贝 。当这个函数运行完后这个形参变回销毁了,不会对实参产生什么影响。
我们调试后可以知道,他们只是地址不一样,那么我们用指针传递地址是不是可以呢?
上代码:
void swap(int* x, int* y) {	int tam = *x;	*x = *y;	*y = tam;}#includeint main() {	int a = 10;	int b = 20;	printf("a=%d b=%d/n", a, b);	swap(&a, &b);	printf("a=%d b=%d/n", a, b);	return 0;}

  我们再调试一下

发现现在x,y的地址和a,b地址相同

这个时候我们通过形参便可以改变实参的关系了。

这个时候可能会有疑问,之前我们的Add加法函数也是是传值调用,为什么还能达到相同的目的呢?第二个swap函数的传值调用为什么不行呢?

我是这样理解的,有return返回值的时候,传值调用和传值调用都可以,但是当没有return返回值,只是执行函数里面的内容是,只有在传址调用时才可以。

我们应该区分出传值调用和传址调用。

总结

传值调用
函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。
传址调用
传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操
作函数外部的变量。

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

函数的嵌套调用就是一个函数里面可以包含使用另外一个函数

eg:

void first() {	printf("hhe");}void seond() {	printf("hdg");	first();}

注*函数可以嵌套调用,但是不能嵌套定义

eg:

void first() {	printf("hhe");void first() {	printf("hdg");	first();}}

这样便是错误的

链式访问
把一个函数的返回值作为另外一个函数的参数
这个也很简单
eg:
int Add(int x, int y) {	return x + y;}#includeint main() {	int a = 10;	int b = 20;	int c = Add(Add(a, b), b);	printf("%d/n", c);	return 0;}

五.函数的声明和定义

函数声明:
1. 告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,函数
声明决定不了。
2. 函数的声明一般出现在函数的使用之前。要满足 先声明后使用
3. 函数的声明一般要放在头文件中的。
函数定义:
函数的定义是指函数的具体实现,交待函数的功能实现。
简而言之    
int  Add()这个是声明,然后后面括号里面具体函数是怎么实现的就是定义
六.函数的递归
什么是递归?
程序调用自身的编程技巧称为递归( recursion )。
递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接
调用自身的
一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,
递归策略
只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归的主要思考方式在于:把大事化小
可能大家不能很好的理解
我举一例子  eg  现要求输入一个数字为1234  我们要在电脑屏幕上一次打印1 2 3 4 
要知道如果是打印4 3 2 1 ,那就很简单了
直接一个循环 先模10 再除10。
思考一下,递归的主要思想是把大事化小,可以这样化,1234 = 123(4)=12(3)(4)
类推,有人可能认为,那还不是依次打印4 3 2 1 嘛
非也非也, 上代码:
void Printf(int x) {	if (x > 9) {		Printf(x / 10);	}	printf("%d ", x % 10);}#includeint main( ){	int m = 0;	scanf("%d", &m);	Printf(m);	return 0;}

 可以观察到,为什么呢?????

 因为刚开始必须全部完成if语句里面的,完成if后才会编译后面的代码,然后if语句里面全都是Printf函数,所以就一直传递,最后不满足条件是才会退出来,然后开始返回,也就是归。

观察我上面的代码可以发现,递归有限制条件,不妨花点时间思考一下?

递归的两个必要条件
存在限制条件,当满足这个限制条件的时候,递归便不再继续。
每次递归调用之后越来越接近这个限制条件

如果这两个条件有一个不满足,会发生什么呢??——栈溢出

这个名词也许你不太熟悉,

 这是电脑中粗存空间的区域名称,而我们在递归中每调用一次函数,便会在栈区开辟一块空间,如果允许计算机一直开辟空间的话,那么区域便会装不下,这样的话学术人员便为这个取了一个名字——栈溢出。

我们试试栈溢出的情况

void Printf(int x) {	Printf(x / 10);			}#includeint main( ){	int m = 20;	Printf(m);	return 0;}       

 

递归先简单介绍到这,稍后博主会在这两天仔细剖析一下递归!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/123193.html

相关文章

  • runc容器逃逸漏洞最强后续:应对之策汇总与热点疑问解答

    摘要:年月日,研究人员通过邮件列表披露了容器逃逸漏洞的详情,根据的规定会在天后也就是年月日公开。在号当天已通过公众号文章详细分析了漏洞详情和用户的应对之策。 美国时间2019年2月11日晚,runc通过oss-security邮件列表披露了runc容器逃逸漏洞CVE-2019-5736的详情。runc是Docker、CRI-O、Containerd、Kubernetes等底层的容器运行时,此...

    PingCAP 评论0 收藏0
  • 架构师之路

    摘要:因为用户不用在第一次进入应用时下载所有代码,用户能更快的看到页面并与之交互。译高阶函数利用和来编写更易维护的代码高阶函数可以帮助你增强你的,让你的代码更具有声明性。知道什么时候和怎样使用高阶函数是至关重要的。 Vue 折腾记 - (10) 给axios做个挺靠谱的封装(报错,鉴权,跳转,拦截,提示) 稍微改改都能直接拿来用~~~哟吼吼,哟吼吼..... 如何无痛降低 if else 面...

    NikoManiac 评论0 收藏0
  • 企业级Android音视频开发学习路线+项目实战+源码解析(WebRTC Native 源码、X26

    摘要:因此,对音视频人才的需求也从小众变成了大众,这更多的是大家对未来市场的预期导致的结果。做个勤奋向上的人,加紧学习,抓住中心,宁精勿杂,宁专勿多。 前言 如今音视频的...

    tomato 评论0 收藏0
  • 从小白程序员一路晋升为大厂高级技术专家我看过哪些书籍?(建议收藏)

    摘要:大家好,我是冰河有句话叫做投资啥都不如投资自己的回报率高。马上就十一国庆假期了,给小伙伴们分享下,从小白程序员到大厂高级技术专家我看过哪些技术类书籍。 大家好,我是...

    sf_wangchong 评论0 收藏0
  • 0x01 念念Python,必有回响

    摘要:摘要灵蛇出现,必有异像,最热的领域,估计非数据分析挖掘领域莫属了。蛇有灵性,蟒蛇更甚。这便是生态圈的力量,不以个人的意志为转移。如若有心,且仔细看图识字念念不忘,必有回响真若有心于数据领域,甚或欲从事数据科学之职业。 摘要:灵蛇出现,必有异像,Python最热的领域,估计非数据分析、挖掘领域莫属了。以Scikit-Learn为代表的数据分析领域,从这里开始,便是Python的天下;一边...

    maochunguang 评论0 收藏0

发表评论

0条评论

_Dreams

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<