函数的详细说明


目录

函数

函数的引入

函数的定义

函数的返回值

有关函数的参数表

函数之间的相互调用

单独文件内的函数调用

多个文件内的函数调用


文前声明:前几篇博客中,我们将C语言基础知识中的大致元素已经详述,接下来我们将对接下来的几个C语言的数据类型进行详细的介绍和讲解。今天我们就将开启函数的海洋,这将是迈向C语言世界的重要一步!

并且在今天这篇博客,我们可以理解C语言中的程序架构都是些什么。

函数

函数的引入

如果是初学者的话,在看到函数想必并不陌生,因为数学领域种也有对函数的定义,但这与我们C语言中的函数并不相同。接下来,我们先去看一段代码:

题目要求:分别为abcd赋值3,4,5,6,在计算和值后输出总值。(单次计算最多只能用两个变量,且同一变量不能出现在两个表达式中)

#include <stdio.h>
int main(){
int a,b,c,d,add1,add2,sum;
a=3;
b=4;
c=5;
d=6;
add1=a+b;
printf("%d",add1);
add2=c+d;
printf("%d",add2);
sum=add1+add2;
printf("%d",sum);
return 0;
}

这段代码中,我们共使用了三次加法,分别是a+b,c+d,add1+add2,这段冗杂的代码,是不遵循我们程序中所要求的基础的简便性的,并且这属于“代码复制”。

代码复制是程序不良的表现,说明程序的质量并不好。如果想成为一个优秀的程序员,这种代码复制是不允许出现的情况,接下来,我们可以利用函数的方法简化这段代码:

#include <stdio.h>
int addf(int a,int b){
int sum;
sum=a+b;
printf("%d",sum);
return sum;
}

int main(){
int a,b,c,d add1,add2,sum;
//赋值操作不赘述,只为演示效果
add1=addf(a,b);
add2=addf(c,d);
sum=addf(add1,add2);
return 0;
}

这种写法十分的新奇,别着急,接下来我们就会揭开函数的面纱。 

函数的定义

在C语言中,函数是一块难以割舍的部分,在C语言程序的运行中,函数的调用是必要的。在数学领域中,函数是用来求解某个值而被调用的一种对应关系。而在C语言程序设计中,函数更像是用来实现一种特定命令的载体。

它通过一段特定的代码,在自己的块内进行狭小的运算,并独立地完成某项指定的功能。

(在某些称谓中,它也被叫做子程序)

声明函数的基本格式如下:
 

Type name(int begin,int ...,int end){
//函数内容
}

函数的定义格式是不是有些眼熟?这就能解释我们从第一章就遗留下来的问题:为什么我们要在每个文件内都写“int main()”?

我们每次在文件中都要写main函数,它被称作主函数,是一个必要的开始端口,主函数中的语句是我们在一个程序中主要执行的相关操作,即便我们后期深入了函数的学习,主函数的地位依然不可动摇,它是一个程序运行的根本。

在这段代码中,蓝色部分是函数头,Type是返回类型(等同于int,doubl等,但没有任何返回结果),name是函数名,int beginint end是参数表。其中,()起到了表示函数调用的重要作用,即使没有参数也需要()。

而我们定义函数的这段代码,有两类可写的区域:
1.主函数前,头文件下方

2.主函数后

(若想要将函数不放在头部而放在尾部,则可以将头函数放在int main()前并加上“;”,将函数定义的全部内容放在主函数的后方,而上方的头函数即是函数的声明,也叫“函数原型”,且其中不用标明参数表的数据名称;下方的头函数和函数体是函数的具体定义)

当然,我们只进行函数的声明而不对函数进行定义的后续补充的话,我们的程序运行是会出现错误的。

函数的返回值

return可以停止函数运行,返回且只返回一个值。

在主函数中,我们有参数值的返回:"return 0"。在我们所定义的函数中,当然也不能缺少。返回值的基本格式如下:

return 表达式;

函数中如果是有需要进行计算并返回的值,则必要的会用到return以此来返回计算的值,若不需要进行值的返回,则可将函数类型定义为空类型(void),以此就可以节省代码段的长度,只进行函数所进行计算反值外的功能性作用。

在我们的主函数中所需要的"return 0"是一些命令执行所必须用到的值,以此来检测主函数是否正确的运行,确保程序的安全,在我们将来所学习的保护程序安全的头文件<assert.h>有着相似的作用。

我们在函数设计理念中的要求是单一出口,所以我们必须要保证返回值的单一性,在部分可能有多个返回值的函数中,我们可能的操作是设置返回值为变量(exiit),以此来保证返回值的可变性从而使得函数的单一出口。

有关函数的参数表

在函数的参数表中,有许多值得注意的细节。

我们的函数只是一片代码,每次运行时,我们的计算机会为函数单独开辟一块空间,供给函数进行相关运算,接受并输出值。因为这种独立性,我们在参数表中所写的值传递只是简单的传值

什么是传值?我们需要理解几个概念:

形式参数:出现在调用函数里的参数,在整个函数体中都可以使用,形参在定义时编译系统并不分配空间,只有在调用该函数时才分配单元。调用结束时内存单元则被释放,故形参只有调用函数时才有效。

实际参数:实参出现在主调函数(main)里,当调用函数时,主调函数将实参的值传给形参,从而实现函数间的传值。

接下来,我们就可以进行传值的讲解了:在主函数将实际参数的值转换成在参数表中已经定义好的形式参数,然后形式参数会以自己的身份在用户所定义的函数体内进行相关的操作。再向外进行计算结果的传递。此时,在主函数中,原来函数的位置就会被替换为本次计算的结果

实参将值单向传递给形参,形参的变化不影响实参值。由此,函数的传值也被称为单向传递

在我们后续的学习中,我们会学到指针。对指针的知识加以应用,我们可以以双向传递的方式进行传值,具体的运用我们会等到指针的详细运用中再讲。指针的运用贯穿了整个C语言!

引用调用:通过指针传递,形参为指向实参地址的指针,对指针操作实际上就是对实参进行操作。)

函数之间的相互调用

单独文件内的函数调用

我们之前说过,主函数是程序执行的窗口,执行源程序就是执行主函数main,其他函数只能被主函数所调用,虽然我们的C语言中函数是不可以进行嵌套定义,但是其他函数之间也可以相互调用。

函数与其他函数的调用:一个被用户定义的函数与另一个被用户定义的函数是可以相互使用的,我们的主函数中使用自己定义的函数就是一个十分常见的例子。

函数与本身函数的调用:这种方式,在我们C语言中,有一种笼统的叫法:递归

一个函数在它的函数体内直接或间接地调用它自身,就是函数的递归调用。多次重复的利用自身函数,是一种十分简单,十分耐用的算法。它的规模较小,只用少数的代码通过重复计算便可描绘出庞大的问题答案。即便有如此优点,层层调用的方式也比较复杂,算法的复杂程度也可想而知。

在进行递归调用的时候,我们必须有明确的规定出口,否则就会使程序出现错误,递归与出口层层逼近,在达到出口后,又会依次逆序将值返回。递归的称谓由此而来。

三言两语难以阐尽递归的奇妙与功能的强大,我们后续会专门在开专栏进行算法与数据结构的解读,到时候递归的穷尽会让我们每一位学者铭记于心。

多个文件内的函数调用

我们在上一节中已经解释过全局变量和局部变量的区别了,在讲函数的全局性和局部性之前,我们需要先对全局变量和局部变量做一个细节的解释。

在上节,我们提到:

虽然十分便利,但是全局变量我们需要特别说明:有其他可替代利用全局变量方法的情况下最好不要使用全局变量!使用全局变量不仅会破坏函数的可移植性,同时还会影响函数的线程!

在本节中,我们可以对此作出解释了:在函数的知识中,函数的最大优点就是可移植性和便携性以及通用性。当函数中有某个文件中的全局变量存在时,当该部分函数被调用到另一个文件中,那么我们的函数将丧失它本该具有的功能!因此,我们不推荐使用全局变量在函数中的应用。

回归本篇,当我们日后从事工作时,难免遇到大型工程项目,这时我们如果还拘泥于仅有的一个执行文件,那我们将面临的可能是上万行甚至更多的代码。同时,我们可能还会因为几个人同时负责同一项目的合作,从而在一个文件的修改中误删了他人的代码,这是十分难堪的场面。

当然,为了解决这个问题,并且可以同时为多个人提供代码的编纂,我们可以将C语言通过特定的方式链接:

回顾我们所讲的变量有extern和static类型,我们的函数也有这两种调用方式:

内部函数(static):也被称为静态函数。仅限了一个函数的使用范围,标志该函数只可在当前所定义的文件内使用,避免了多个函数重复出现的错误。

外部函数(extern):也被称为动态函数。声明一个函数原型,默认为extern,只要在一个文件中有定义,就可以在其他文件中进行调用,不过需要加上extern前缀进行外部函数声明。

当然,这些都是我们所定义的函数。

有没有注意到那所谓的"#include <stdio.h>"?那就是在调用我们的头文件。#include是一个预处理指令在编译开始前,我们的编译器会率先将该地方与调用的头文件内容进行完全意义上的文本替换,进行编译预处理

头文件(.h):一般只有声明会放在头文件中,把声明放到头文件中,,在需要调用这个函数的源代码(.c)文件中#include这个头文件,就可以让编译器在编译时知道这个函数原型,在使用或者定义这个函数的地方都要有头文件,但需要攥写的地方不需要头文件声明

除了我们定义的函数外,还有一些C语言系统本身就带有的一部分函数,那就是我们的库函数。我们的库函数中有着平时常用的函数声明,系统自带的库函数中所带的函数可以完成我们的很多需求,轻松的帮助我们实现预期的功能,方便程序员进行软件开发,例如:

printf("Hello world");

输出函数就帮助我们便捷的提供了打印内容在屏幕上的效果,它是属于我们stdio.h文件中所定义的函数。

我们常用的库函数有IO函数,数学函数,字符串函数等等,如果有时间,我们会在日后单独讲解它们各自的作用,并进行相关的汇总。

tip:我们需要知道,头文件中所放的并不是函数的库,只是函数的声明,函数库在一个后缀为.lib的文件中。

#不是C语言的成分,但C语言却离不开它们。


至此,我们本篇函数部分的详细讲解到此结束,感谢大家的支持!在学习的山峦中只有不停的跋涉,才能有更高的成就!

那么,我今天的博客到此为止,感谢您认真看完了本篇小白编写的博客,以上均为本人理解,如有错误欢迎在评论区指出。

虽然基础薄弱,但今天仍是在幻想成为大佬的一天。

山高路远时,找不到答案的话,就去寻找自己

  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

励志做大佬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值