forum.jpg

在前面文章中对C语言中的基本数据类型、运算符及优先级和程序结构做了详细讲解,这一部分将讲解C语言中的重要组成部分:函数 。预计用4-5篇文章来讲述函数。
(1)为什么需要函数?
在前面的的测试代码中,因为功能简单只需一个main函数就能完成任务。但是如果功能比较复杂,还是只有一个main函数的话。那么代码会变得非常的多,不便于阅读和维护。这个时候就需要把复杂的功能分成若干个独立的小功能(小模块)来实现,这个小功能(小模块)就称之为函数。还可以提高可移植性。要注意这里所说的“模块”,模块其实是一种手段也是一种思想,要好好体会一下,将来Linux驱动编程中还会用到。模块化编程便于把复杂的功能碎片化,使得一方面在公司中每个人可以完成整个项目的一部分,另一方面也有利于阅读和维护代码。所以提倡大家在头脑中要有“模块化编程”的思想。
前面的所有测试代码中都有2个函数:main和printf main()函数比较特殊又重要并且有且只有一个,它是整个程序的入口,被操作系统来调用,其他的函数被main函数直接或者间接调用。printf()函数是格式化输出函数, 一般用于向标准输出设备按规定格式输出信息。它是系统提供的库函数,通常包含在stdio.h文件中。可以使用man 3 printf命令查找它的详细信息。
(2)什么是函数?需要哪几部分组成?
涉及到函数的几个概念:函数的定义、函数声明、函数调用
1)函数定义:函数体的实现。这个函数体就类似于循环结构中的循环体,是用大括号{}括起来的一段代码段。
函数定义形式:函数返回类型 函数名(函数参数列表){函数体}
函数返回类型就是前面多讲的基本数据类型,比如int、char、float、double等,也就是执行完这个函数后,返回相应数据类型的值,在函数体的内部用return关键字来实现,比如return a;这个变量a的类型和定义函数时的函数返回类型一样 。 return语句允许从函数体的任意位置返回,并不一定要在函数体的末尾。如果函数不需要返回值那么在函数定义或者声明时用void关键字表示。void关键字的详细用法在后续讲解。 return后面的语句也可以加上小括号(),比如return (a);
函数名就是函数的名字,将来在函数声明和调用时会用到
函数参数列表就是向函数所传递的参数,有参数类型和函数参数名组成。参数可以有多个(多个参数用逗号隔开)如果没有参数用void关键字,每个参数都有相应的数据类型,但是一般编写函数时参数不要多余4个,否则对阅读和维护代码比较麻烦。
参数有2种:形参和实参 形参就是形式参数的简称,在函数的定义和函数声明中会用到。 实参就是实际参数的简称,在函数调用时会被用到。如果函数没有参数,可用void关键字来表示,记住void它并不是表示有一个类型为void的参数。
在一个文件中完全相同的函数名定义只能有一次,如果定义多次会出现 error: redefinition of ‘xxx’,(xxx是函数名)但是声明可以多次。
2)函数声明:也就是函数的原型即把函数定义中的将{}和所包含的函数体去掉,在后面加上分号;即可。这个分号也是区别函数定义和函数声明的重要标志。主要是为了在函数调用时提示编译器,让编译器检查函数的参数及类型,如果有返回值的话也检查相应的返回值。如果函数定义和函数调用不一样,那么可能就会提示报错,便于我们查找出错的地方。
如果没有函数声明,编译器默认返回值为整型并且会假定参数类型和个数都没有错,那么对于返回值为整型的函数来说,这时候也不会出错。如果代码的返回值不是整型,没有声明会导致结果为整型,从而使得计算结果错误。所以一定要记得对函数进行声明。
在函数声明时函数类型必须写,函数参数名可以不写,但是加上函数参数有时候可以提供更详细的信息给阅读代码的人。
那么什么时候需要函数声明以及声明的位置?如果在函数的定义出现在main函数之前,则不需要声明,否则需要声明。对于只需要main.c文件就可以实现功能来说都会把函数定义放在后面,前面就需要相应的声明。另外一点,我们在模块化编程时,比如一个.c和一个.h文件相对应。我们会在.c文件中定义函数(前提是这个外部要使用这个函数),在.h文件中声明函数,以便于别的代码中使用#include来包含这个头文件。这样即便函数的定义需要修改,只需要在.c中和.h中修改,而被用#include来包含这个头文件的地方不需要修改。
3)函数调用: 调用函数名来实现相应的功能,在调用函数时函数返回值类型、函数名和函数参数及类型、顺序一定要一致。
在函数调用时要注意“传值”和“传址”。传值是将传递过过来的实参进行复制一份,函数中的函数体可以随意修改这个值,而不影响原来实参的值;
而“传址”后如果在函数体内修改这个值,那么原来实参的值也会改变。这里先不讲“传址”,因为涉及到还未讲的“指针”部分。后面的演示代码中用的就是“传值”。
(3)测试代码 代码如下图所示:
1)测试函数的定义、声明、调用。
forum.jpg
测试函数代码
2)如果函数的返回值不是整型,如果不声明就会报错,如下图所示:
forum.jpg
测试函数代码
forum.jpg
没声明函数报错信息