本篇文章我们来到函数相关的内容,每个项目中的代码里面函数是必不可少的,代码中有了函数的存在变得十分有条理、十分美观,有利于开发人员的阅读。
在C语言中,函数是构成程序的基本模块。程序的执行从main()的入口开始,到main()的出口结束,中间循环、往复、迭代地调用一个又一个函数。每个函数分工明确,各司其职,对这些函数而言,main函数就像一个总管。C语言中函数包括标准库函数和自定义函数,这里我们主要讨论自定义函数。
自定义函数基础
定义一个函数必须包括返回值类型、函数名、形式参数及其类型和函数体,但是在程序中大单独有个函数并不会运行,我们必须在main函数中调用,必要时我们需要在main函数中传一个实际参数进去,当然并不是只有在main函数中才能调用函数,自定义函数中也可以调用函数,调用其他函数称为主调函数,被调用的函数称为被调函数,这里涉及到函数的嵌套,后面我们会慢慢涉及,先来段简单的代码来看看:
在int addfunc(int a,int b)中,开头的int就是函数返回值类型,addfunc就是函数名,int a、int b就是形参及其类型,花括号里的就是函数体,在main函数中调用这个函数,实现加法运算,要注意的是main函数中的a,b和addfunc函数中的a,b是不同的数,main函数中的a,b就是实际参数。
接下来我们就来看看形参和实参的区别:
很明显我们可以看出来,主函数和我们自定义函数中的参数虽说值是相同的但是地址不同,这就意味这我们如果在自定义函数中修改一个变量的值,最后在主函数中打印出来,值其实是不变的:
可以看到changedata()中打印的data的值改了,但是主main函数中的data的值依旧未变,因为这两个data的地址是不同的,所以要想在自定义函数中把主函数的值改变,那我们传参的时候就得传地址,下面我们就来看一个经典的程序:
这里我们就是把a和b的地址传到了swap()这个自定义函数中,所以我们在swap()中就能成功交换a和b的值。大家也可以去试一下不传地址去看下输出的结果。
函数的嵌套和递归
函数的嵌套其实很好理解,就是在函数中再调用函数,在我们做项目的时候函数嵌套也是必不可少的,把每一个模块实现的功能封装成一个函数,而模块与模块之间又有联系,有可能一个模块中需要调用另一个模块才能实现完整的功能,这就是函数嵌套。这里我们就简单实现一下函数的嵌套:
代码大家应该能看明白,在这里就不多解释了。
函数的递归简单理解就是这个函数直接或间接调用自己,直接上代码:
这个函数的功能就是实现阶乘,就需要用不断调用自己,至于这里为什么要long long int是因为用int的话会溢出,要注意的是用long long int,printf()时要用%lld。
函数传参之数组
当我们要传的参数为数组的时候要怎么办呢?这个其实不难,但是容易在细节上出点小问题,整体上和普通传参大同小异:
我们可以看到,把数组当作参数传递自定义函数中时我们只需要传数组名,数组名就表示数组首元素地址,在定义函数时我们写得是int array[ ],中括号里面的元素个数可以省略。大家仔细看下这段代码,我们还打印了数组在主函数和在自定义函数中大小,可以看到main函数中数组的大小由其类型和元素个数决定,而自定义函数中数组大小是恒定的 。这里要注意:在形参中其实是不存在数组的概念的,即使我们这里写成了int array[ ]这样的形式,但是实际上这是地址,首元素的地址,在操作系统里由8个字节表示一个地址。
上面提到传递数组其实传递的是一个地址,那么我们看看这段代码:
大家应该还有印象吧,上文我们在自定义函数中实现data = data + 100,最后主函数的data值仍然不变,但是看看现在这段代码,不论是主函数还是自定义函数中,arr[1]的值都变了,这就更好地说明了传递数组就是传递指针。
讲完一维数组,我们来聊聊二维数组的传参,直接上代码吧:
这里要注意的是二维数组传参是和其定义时一样,它的列维度[ ]里的数字不能省略,其他的其实也差不多,就不过多赘述了。
全局变量
全局变量不在任何语句块内定义,其作用域为整个程序。我们来看个例子:
函数的返回值一般只有一个,像这个程序既要找到最大值,又要找到对应的下标,我们就可以借助一个全局变量来接受这个下标,这个函数理解起来应该不难。
至此,本片就结束了,下一篇就进入指针了,是C语言的核心内容了,希望各位小伙伴一起加油,共勉。