一,函数分类:自定义函数,库函数
对于库函数:1,I/O函数:用于计算机的输入输出
2,字符串操作函数:用于对字符串进行操作
3,字符操作函数:用于对字符进行操作
4,内存操作函数
5,时间/日期操作函数
6,数学函数
7,其他库函数
下面举几个例子:strcpy(字符1串数组名1,字符串数组名2/字符串),将后面的内容赋粘贴到前面,并且前一个里面原本内容被覆盖掉
menset函数:
memset中有3个变量,第一个变量是要操作的字符串组,第二个变量是设置什么值,第三个变量是前几个字符要设置成这个值。
对于库函数的学习主要是通过看一些网站,下面推荐几个学习库函数的地方:
3,MSND软件
二,自定义函数:
基本语法:返回值类型 函数名字 (传入类型 名字)
{
函数体
}
对于不需要返回值的函数,返回值类型处写void
参数类型:
1.形式参数:函数名后面括号内写的参数,没有实际空间,当函数调用时,才会分配内存,并且跳出函数就销毁。
2.实际参数:传递个函数的参数,可以是具有确定值的常量,表达式,变式,函数等。
下面写一个用于交换两个数字的程序:
你可能写的函数:
这个函数表面上看你是进行了数据的交换,但是你调用的时候并不会对你原来的数据进行交换。
这是为什么呢?这与函数的传入类型有关:1,传值函数。2,传址函数
传值函数:传入数值,实参和形参占据不同的内存块,对形参的改变不会影响实参
传址函数:传入实参的地址,让函数与外部变量建立联系,实现在函数文件中对外部变量进行修改。
上面这个代码只是在函数内部对形参进行修改,并不会交换实参的数值,因此出来函数,无法实现对实参的修改。
接下来解决这个问题:(写一个传址函数)
这个函数,需要注意的是,传入的是指针变量,也就是实参的地址,在原始地址上实现对外部数据的交换,并非开辟一个新的空间。
三,几个关于函数的练习:
1,判断素数:
2,判断闰年:
3二分查找
在这程序中需要注意的是如果向一个函数中传入一个数组,相当于是传入数组第一个数据的地址,之后调用这个数组中的其他数据是依靠这个地址进行往下调用。
4
在函数内部改变实参,需要传入地址
四,函数的嵌套调用和链式访问
嵌套调用:在一个函数里面可以调用另一个函数,例如
链式访问:一个函数的返回值作为另一个函数的参数。例如:
再如:
大家可以猜一下这个最终打印的内容是啥(提示:printf函数返回值是打印内容字符的个数)
这样很容易就想到:4321
五,函数的声明与定义:
如果函数写在主程序后面,执行代码的时候,编译器由前往后扫描,会出现警告,告诉你函数没有定义,这就需要在主程序前面对这个函数进行声明,告诉编译器你有这个函数,例如:
如果是写在一个源文件中,直接将函数定义在主程序的前面不就行了,何必多此一举呢?
的确,因为函数的定义与声明主要是用在不同的源文件中,即将函数单独写在一个源文件,再写一个与其对应的头文件,之后再在主函数中通过声明头文件,可以对函数直接调用,
Add函数写在一个名叫add.c的另一个源文件中。
头文件中写声明:格式
ifndef 和define 后面的ADD部分是根据你的头文件名称而有所改变的,就是你头文件英文大写
声明上下的内容,保证头文件不会被多次引用,占用空间。
六,函数的递归
递归:程序调用自身的编程技巧称为递归,递归作为一种算法在程序设计语言中广泛应用。一个个过程或者函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂问题转化为一个与原问题相似的规模较小的问题来解决,递归策略只需要少量的程序就可以描述出解题过程所需要的多次重复计算,大大减少代码量。主要思考方式:大事化小。
下面看一个简单的递归:
这个程序会一直打印hehe,直到栈溢出(Stack overflow)
看一下什么叫栈溢出:
这个程序一直运行,产生的局部变量和形参会将栈区的内存用完,就产生的栈溢出。
函数递归的两个必要条件:1,存在限制条件,当满足时,递归不再继续。
2,每次递归调用后越来越接近这个限制条件。
实例
写一个递归,计算字符串长度