1.为什么要使用函数
如果程序的功能比较多,规模比较大,把所有的程序代码都写在一个主函数(main函数)中,就会使主函数变得庞杂、头绪不清,使阅读和维护程序变得困难。此外,有时程序中要多次实现某一功能(例如打印每一页的页头)就需要多次重复编写实现此功能的程序代码。这使程序冗长、不精炼。因此,人们自然会想到采用“组装”的办法来简化程序设计的过程。如同组装计算机一样,事先产生好各种部件(如电源、主板、硬盘驱动器、风扇等),在最后组装计算机时,用到什么就从仓库中取出什么,直接装上就可以了。绝不会采用手工业方式,在用到电源时临时去生产一个电源,用到主板时临时产生一个主板。这就是模块化程序设计的思路。
在设计一个较大的程序时,往往把它分为若干个程序模块,每一个模块包括一个或多个函数,每个函数实现一个特定的功能。一个C程序可由一个函数和若干个其他函数构成。由主函数调用其他函数,其他函数也可以互相调用。同一个函数可以被一个或多个函数调用任意多次。除了可以使用库函数外,有的部门还编写一批本领域或本单位常用到的专用函数,供本领域或本单位的人员使用。在程序设计中要善于利用函数,以减少重复编写程序段的工作量,也更便于实现模块化的程序设计。
2.怎样定义函数
C语言要求,在程序中用到的所有函数,必须“先定义,后使用”。例如想用max函数去求两个数中的大者,必须事先按规范对它进行定义,指定它的名字、函数返回值类型、函数实现的功能以及参数的个数与类型,将这些信息通知编译系统。这样,在程序执行max时,编译系统就会按照定义时所指定的功能执行。
定义函数应包括以下几个内容:
(1)指定函数的名字,以便以后按名调用。
(2)指定函数的类型,即函数返回值的类型。
(3)指定函数的参数的名字和类型,以便在调用函数时向它们传递函数。对无参数函数不需要这项。
(4)指定函数应当完成什么操作,也就是函数是做什么的,即函数的功能。这是最重要的,是在函数体中解决的。
对于C编译系统提供的函数库,是由编译系统事先定义好的,库文件中包括了对各函数的定义。程序设计者不必自己定义,只须用#include指令把有关的头文件包含到本文件模块中即可。在有关的头文件中包括了对函数的声明。函数库只提供了最基本、最通用的一些函数,而不可能包括人们在实际应用中所用到的所有函数。程序设计者需要在程序中自己定义想用的而函数库并没有提供的函数。
3.定义函数的方法
1.定义无参函数
定义无参函数的一般形式为:
类型名 函数名()
{
函数体
}
或
类型名 函数名(void)
{
函数体
}
函数名后面括号内的void表示“空”,即函数没有参数。
在定义函数时要用“类型标识符”(即类型名)指定函数值的类型,即指定函数带回来的值的类型。
2.定义有参函数
定义有参函数的一般形式为;
类型名 函数名(形式参数表列)
{
函数体
}
函数体包括声明部分和语句部分。
例如,定义max函数的有参函数:
<span style="font-size:14px;"><span style="font-size:14px;">int main (int x ,int y)
{
intz ;
z= x > y ? x : y;
return (z) ;
}</span></span>
3.定义空函数
在程序设计中有时会用到空函数,它的形式为;
类型名 函数名()
{}
例如:
voidmain()
{}
函数体是空的。
4.函数调用的形式
定义函数是为了调用此函数,函数调用的一般形式为:
函数名(实参表列)
如果是调用无参函数,则“实参列表”可以没有,但括号不能省略。如果实参表列包含多个参数,则各参数间用逗号隔开。
5.函数调用时的数据传递
1.形式参数和实际参数
在调用有参函数式,主调函数和被调用函数之间有数据传递关系。在定义函数是函数名后面括号中的变量名成为“形式参数”或“虚拟参数”。在主调函数调用一个函数时,函数名后面括号中的参数称为“实际参数”。实际参数可以是常量、变量或表达式。
2.实参和形参间的数据传递
在调用函数过程中,系统会把实参的值传递给被调用的函数的形参。或者说,形参从实参得到一个值,该值在函数调用期间有效,可以参加函数中的运算。
例,输入两个整数,要求输出期较大者。
<span style="font-size:14px;">#include <stdio.h>
int max (int x ,int y)
{
int z ;
z = x > y : x ;
return (z);
}
int main ()
{
int max (int x ,int y) //对max函数的声明
int a ,b ,c ;
printf (“输入两个整数:”);
scanf (“%d,%d”,&a,&b);
c = max (a,b); //调用max函数,有两个实参。
printf (“较大值为%d”,c); //输出较大值
return 0 ;
}
</span>
6.函数的调用过程
1.在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元。在发生函数调用时,函数max的形参被临时分配内存单元。
2.将实参对应的值传递给形参。
3.在执行max函数期间,由于形参已经有值,就可以利用形参进行有关的运算(例如把x和y比较,把x或y的值赋给z等)。
4.通过return语句将函数值带回到主调函数。例如在return语句中指定的返回值是z,这个z就是函数max的值(又称返回值)。执行return语句就把这个函数返回值带回主调函数main。应当注意返回值的类型与函数类型一致。如max函数为int型,返回值是变量z,也是int型,二者一致。
5.调用结束,形参单元被释放。注意:实参单元仍保留并维持原值,没有改变。如果在执行一个被调用函数时,形参的值发生改变,不会改变主调函数的实参的值。
注意:实参向形参的数据传递是“值传递”,单向传递,只能由实参传给形参,而不能由形参传给实参。实参和形参在内存中各占有不同的存储单元,实参无法得到形参的值。
7.函数的返回值
通常,希望通过函数调用是主调函数能得到一个确定的值,这就是函数值(函数的返回值)。
1.函数的返回只是通过函数中的return语句获得的。Return语句将被调用函数中的一个确定值带回到主调函数中去。如果需要从被调用函数带回一个函数值供主调函数使用,被调用函数中必须包含return语句。如果不需要从被调用和函数带回函数值可以不要return语句。
例如,
void print_star ()
{
printf(“itheima”);
}
一个函数中可以有一个以上的return语句,执行到哪一个return语句,哪一个return语句就起作用。return语句后面的括号可以不要,return后面的值可以是一个表达式。
例如,
int max (int x ,int y)
{
return (x > y ? x : y);
}
等价于
int max (int x ,int y)
{
int z ;
z = x > y ? x : y ;
return (z);
}
2.函数值的类型。既然函数有返回值,这个值当然应属于一个确定的类型,应当在定义函数式制定函数的类型。例如:
int max (int x ,int y) //函数值是整形
char letter (char c1 ,char c2) // 函数值是字符型
double min(int x ,int y) //函数值是双精度型
注意:在定义函数时要制定函数的类型。
3.在定义函数式制定的函数类型一般应该和return语句中的表达式类型一致。如果函数值的类型和return语句中的表达式的值不一致,则以函数类型为准。对数值型数据,可以自动进行类型转换。即函数类型决定返回值的类型。
例如,如果函数返回值的类型与指定的函数类型不同,按照赋值规则处理。
#include <stdio.h>
int main ()
{
int max (float x , float y)
float a ,b ;
scanf("%f,%f",&a,&b);
c = max (a,b);
printf("max is %d \n",c);
return 0 ;
}
int max (float x , float y)
{
float z ; // z为实型变量
z = x > y ? x : y ;
return (z);
}
8. .h文件和.c文件的分工
1. 单文件的坏处
l 一个文件的内容太多,不利于阅读、调试
l 多人修改同一个文件出问题
l 公司里面是团队合作
2. 将sum函数抽取到另一个.c文件中
l 先直接调用sum函数,编译警告、链接main.c错误
l #include “sum.c” ,编译链接main.c,运行成功(画图分析.o文件中的东西)
l 如果avr.c中使用sum.c,编译链接main.c,运行程序(画图分析出错原因)
3. 在其他文件中声明sum函数
l int sum(int,int);
l 编译链接main.c
l 编译链接sum.c
l 编译链接main.c sum.c,运行成功
l avr.c利用一样的方法
4. 将int sum(int,int)抽取到另外一个文件中
l 不抽取声明的坏处:增加新的函数了
l 抽取到.c文件中?开发工具会将所有的.c进行编译链接
l 抽取到.h文件中
5. 抽取步骤总结
l .c文件写函数的定义
l .h文件写函数的声明
l 要想用我的函数,请包含我的.h文件
l 好处分析
9. #include
预处理指令简介
·#include的作用
作用:拷贝右边文件的所有内容到#include所在的位置
·stdio.h中有什么?链接的时候做了什么事情
#include <stdio.h>的目的:拷贝printf函数的声明
· <>和””的区别;
自定义的文件用"",系统自带的文件用<>
· #include的路径问题
默认是同路径,其他问题以后再讨论
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------