在数学的学习过程中,我们经常与函数这个概念打交道。什么幂函数,指数函数…它们都有共同的基本结构:自变量,因变量,函数表达式。那么C语言中的函数也是这样吗?让我们通过这一站的学习,来了解了解C语言中的函数
1.函数是什么
维基百科中对函数的定义是: 子程序
在计算机科学中,子程序是一个大型程序中的某部分代码, 由一个或多个语句块组成。 它负责完成某项特定任务,而且相较于其他代 码,具备相对的独立性。
一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库。
2.函数的分类
(1)库函数
在目前的学习中,有一些我们经常用到的功能,如: 输入,输出,开平方,等等。向上面这些描述的基本功能, 是我们每个程序中都有可能用到的,C语言提供了一些库函数, 楷体为了支持可移植性和提高程序的效率,方便程序员进行程序开发
那我们应该怎样学习库函数呢?
在这里,推荐一个网站
C语言语言官网 http://www.cplusplus.com/
打开这个网站之后,要回到就版本才能进行搜索,新版本功能还不是很完善。要进行下图操作才能回到旧版本
在这里,我以strcmp函数为列子向大家展示如何学习库函数
路漫漫其修远兮,吾将上下而求索
当然,这些库函数有很多,但是,我们并不需要全部都记住, 要学会使用工具去查询,在这里,我再推荐几个网站
1.英语版
2.中文版
注意:
1.库函数必不可少的就是要引用头文件,(相当于你用了别人的东西,要给给别人说一声,要不然就认为是偷的)----这里可以联想到声明外部变量,声明外部函数,变量的声明,函数的声明
2.引用库函数头文件的形式—#include<对应的头文件>
引用自己定义的函数—#include “函数名.h”
(2)自定义函数
库函数只能完成一些特定的基础功能,如果,我们有自己格外的需求,那么库函数就不够用了。这时,就需要我们自定义一个函数。其实,自定义函数与库函数有着相同的构成:函数名,返回值类型,函数参数
接下来,我们用一个函数来了解自定义函数的基本构成与调用
在这里,我们要注意:
1.函数的定义是可以不加变量名称的,只需要传一下变量类型
2.函数的调用是不需要函数的类型,要不然会报错的,如下图:
我们已经知道了自定义函数的基本知识之后,让我们来一点有难度的构造函数
交换两个整形变量
让我们来看一下运行结果是否和我们想的一样
这并不是我们想要的,两个整数并没有进行交换
C语言程序有问题,那就要问内存空间—问他有么有开辟出来一块空间,问他是不是溢出了。
那么,我们来看看参数的内存分布吧
由此,我们可见:
a 跟 x ,b 跟 y 的内存不是一致的。
相当于我买了东西,但东西送错人了。我们在swap函数内对 a ,b 进行操作,进行换值,对于主函数内的 x, y根本没有影响。-----因为这两者没内存之间的关联度,我的数值变了,对另一个来说,根本没有影响
接下来,我们的解决方法是传地址过去,用指针来接收。那么它们的地址就有关联度了。
来看看运行结果:
那么,我门就来总结一下:
1.函数传参有两种形式,一是传值,二是传址
2.传值:函数运行起来后,形参是形参,实参是实参,形参和实参没有任何关联性,改变形参时,不会对实参造成任何影响
3.传址:形参指向的实体是实参,对形参解引用后,拿到的内容就是实参,因此对形参解引用之后的内容进行修改,改变的就是实参
4.传参时不论是按照值还是指针方式传递,形参拿到的都是实参的一份拷贝.在程序没有运行到自定义函数时,形参就不会有内存单元(或者说是形参就不复存在),运行到函数时,形参才会真正有它的内存单元,但出了函数之后,内存单元也就销毁了
3.函数参数
其实,上面我们就已经涉及到形参和实参的概念。接下来,让我们更好地了解形参和实参
以上面的一段程序当做列子
1.实参-----真正传给函数的参数
实参的类型可以有:常量,变量,表达式,函数等等
2.形参-----函数名后面括号中的变量
因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效
在这里,形象地解释一下什么叫实例化-----原本这个形参是不存在的,只有当程序运行到调用该函数的时候,才给它分配内存空间,才能来接收实参传过来的数据。所以,我们可以认为形参实例化之后其实相当于实参的一份临时拷贝
4.函数调用
注意:
1.调用之前,一定要声明-----联想到库函数的调用(引用头文件),外部函数的声明(extern + 函数名 (参数类型)),外部变量的声明(extern 变量名),函数的声明
2.分类:
(1)传值调用-----把实参的值拷贝了一份过去,形参实参之间并没有内存之间的联系。改变形参并不 会改变实参
(2)传址调用-----形参实参之间的内存是有联系的,改变形参会改变实参
3.传址调用和传值调用都是实参的一份临时拷贝
5.函数的嵌套调用和链式访问
函数和函数之间可以根据实际的需求进行组合的,也就是互相调用的
(1)嵌套调用
函数可以嵌套调用,但是不能嵌套定义。如:
运行结果:
(2)链式访问
把一个函数的返回值作为另外一个函数的参数
我们在这里举两个列子:
第一个例子
注意:
1.把strlen函数的结果返回值作为printf函数的参数进行运算
2.strlen函数:计算字符串的长度,空格的长度也要加上哦
第二个例子
补充:printf和scanf函数在作为参数的情况下,返回值是所读取有效数据的个数
在这里,我们。可以发现:scanf和printf函数中的有效数据不包括空格
我们来对这个函数进行剖析:
运行开始-----是从最内层的 printf函数 (即编号1)开始的
编号为3.的 printf函数 在屏幕上打印了 54 ,并向编号为 2 的 printf函数 返回了 2 作为参数
编号为2.的 printf函数 在屏幕上打印了2 ,并向编号为 1 的 printf函数 返回了 1 作为参数
编号为1.的 printf函数 在屏幕上打印了 1
总结下来:在屏幕上打印了-----5 421
6.函数的声明与定义
1.告诉编译器有一个函数叫什么,参数是什么,返回类型是什么,
2. 函数的声明一般出现在函数的使用之前。要满足先声明后使用。
3. 函数的声明一般要放在头文件中的
函数的定义是指函数的具体实现,交待函数的功能实现
一般,在一个工程中,把函数的声明放在头文件中,把函数的定义(实现)放在源文件中,再来一个源文件用来测试
好了,好了。今天不开心的事就忘掉吧,看我的博客要开开心心地汲取知识哦!