第一节 函数的定义
知识点:函数的定义法则;
重要程度:★★★
概念题目:
1、C语言的程序设计中,基本组成单位就是函数。一个特定的函数是具有独立功能的C语言代码块,用于完成特定的运算任务。
2、一个C语言程序,可以由一个或多个函数组成。但是一定要注意:在一个程序中只能有一个main函数,无论其位置如何,总是程序开始运行的地方。
3、函数最大的用处是完成某项功能,函数可以用来解决相同的问题,这样可以减少重复编写的工作量,提高整个程序的可读性。
4、函数的返回值默认情况下为int。
5、在一个函数的函数体中不允许再定义新的函数。
6、函数使用两种规则:第一要求先定义,后调用。第二先声明,再调用,后定义。
练习题:以下叙述中错误的是( )。c
A)C语言编写的函数源程序,其文件名后缀可以是.C
B)C语言编写的函数都可以作为一个独立的源程序文件
C)C语言编写的每个函数都可以进行独立的编译并执行
D)一个C语言程序只能有一个主函数
1、函数的定义
我们看到函数一般形式的定义如下:
函数返回值的类型名 函数名 (类型名1 形式参数名1,类型名2 形式参数名2,……)
{
说明部分
语句部分
}
在定义的形式中,第一行整体称之为函数的首部,圆括号中的形式参数简称为形参。函数体是指一对花括号括起来的部分,函数体中的主要功能是完成函数中需要使用的变量的定义说明、完成必要的功能的代码,也就是完成函数功能。
例1:一个用来计算两个整型数据相加的函数。
int add(int x,int y)
{
int z ;
z=x+y ;
return z ;
}
对照函数的一般形式定义,我们可以知道该例中:
函数返回值的类型名:int 函数名: add
类型名1 形式参数名1: int x 类型名2 形式参数名2: int y
说明,语句部分:int z ;
z=x+y ;
return z ;
说明:
1)函数的返回值实际上就是函数的运算结果。当函数返回值的类型名缺省时,返回值类型默认为int类型,而不是无返回值。如果要函数只是进行运算,不要有运算结果,也就是要函数没有返回值,那么类型名应为void。
2)函数名实际上相当于人的姓名,是用户定义标识符。在同一程序中,函数的名称必须互不相同。主函数的函数名必须为main,且只有一个。
3)如果函数没有形式参数,也没有函数体具体的实现,那么这个函数就叫做空函数。如下面的函数wangcheng就是一个空函数:
wangcheng( )
{
}
对形参的一点说明。
形参与这些变量都是属于这个函数的。是函数被使用的时候临时分配的,一旦函数使用完毕,这些空间均被释放。它们作用的范围也只是本函数内,因此可以与其他函数的变量、形参同名。例如例1中,变量x、y、z都是属于函数add的,那么与其它函数中出现的x、y、z是不冲突的,同时,当add函数使用完成后,x、y、z使用也就完成,系统会自动把x、y、z释放掉。
第二节 函数的返回值
1、函数的返回值(考试重点)
1、函数的返回值实际上就是函数运行的结果。
2、如果要求函数没有返回值,即返回值类型为void。
3、一个函数可以有多个return的语句,但是每次调用函数,只有一个return语句被执行。程序一旦执行return语句就会结束当前函数的运行,其作用有些类似于循环结构中的break语句。
4、一对圆括号可以缺省。以下的返回方式都正确return z; return x+y; return (x+y) 直接写上一个数值也是对的,如return 9。所以我们记住:return 是返回函数计算得到的结果。
5、函数的返回值就是表达式的值,返回值的类型必须与函数首部中返回值的类型一致。否则系统将强制的以首部中的类型为准。(近几年考得很多)
int add(float a, flaot b)
{
float c;
c= a+b;
return c;
}
这个地方注意虽然是return c为整型,但是函数首部中是int,最后是以首部为准,就是返回一个整型。
例1:定义一个求矩形面积的函数:
double recarea ( double x, double y)
{ double area;
area=x*y;
return area;
}
在这个函数中:
1) 函数的首部是double recarea(double x, double y)。该函数的返回值类型为double,函数名为rearea,一共有2个形参,类型都是double,形参名分别为x,y。
2) 函数体部分中定义了一个double类型的变量area,它是用来存放矩形的面积。也就是把两个形参的乘积赋值给它。
3) 该函数是要有运算结果的,且结果是矩形的面积。也就是我们要把变量area中的内容作为函数的运算结果,这个是通过return area 语句完成的。
4) 该函数实际解决的问题是:只要知道了矩形的长和宽,就可以通过recarea函数求得矩形的面积。每次可以传递不同的长和宽的数值给recarea函数,这个叫做函数的调用,后面会详细介绍。
例2:以下isprime函数的功能是判断形参a是否为素数,如果是素数,函数返回1,否则返回0。请填空。本题是2006年4月的考题,考察点return语句的使用,难度适中。
int isprime(int a)
{ int i;
for(i=2;i<=a/2;i++)
if(a%i==0) ;
;
}
分析:
从函数的首部了解函数名、函数的返回值类型、函数的形式参数。可知:返回值类型int,函数名isprime,形参为int类型,形参名字为a。在函数体中,定义一个int类型的变量i,后面语句部分是判定素数的方法:判断一个整数是不是素数,就要看除了1和它本身外,还有没有能被它整除的整数。
循环的变量i要从2开始一直到a/2,一旦有一个i能被a整除,那么a就不是素数。题目要求不是素数,函数返回0。所以if条件后面a%i==0表示a整除i,所以不是素数,应该填写return 0。如果整个for循环结束了if的条件a%i==0都为假,即表示没有哪一个i能被a整除,a必为素数,返回1。因此后面应填写 return 1 。
注意:执行了return语句后就会退出函数,不会再执行后面的语句,所以该函数虽然有两个return语句,但是每次只会执行一个return语句。
第三节 库函数
知识点:库函数的使用;返回类型、数值;形式参数的类型、个数;
重要程度:★★★★
库函数是不需要用户自己去编写,对于这些函数,用户不需要定义,就可以直接使用。
需要注意:
1) 不同的库函数放在不同的库中。所以使用某一类库函数的时候,首先要打开这个库才可以使用里面的库函数。打开库函数的方法是:在程序的开头使用include命令包含头文件。例如:printf函数是库函数,它是属于库“stdio.h”的。所以使用printf函数要在程序开头加上#include "stdio.h"。再举一个例子:在C语言中有一些处理数学方面的函数,如求根函数(sqrt函数)或求绝对值函数(abs函数),这些函数是放在库“math.h”中的。使用这些函数就必须在程序开头加上如下命令:#include "math.h"。
2) #include "stdio.h",其中的""也可以用一对< >代替:#include <stdio.h>
3) 库函数要掌握的是其使用的方法,返回的数值、参数的个数、参数的类型。
4) 打开库函数#include "stdio.h"的后面是不要写分号的。
5)常考的库函数:(考试重点)
1、sqrt(4) 返回√4的值
2、fabs(x) 返回双精度参数x的绝对值
3、pow( 2,3) 返回23的值(考得是最多的)
4、exp( 3 ) 返回指数函数e3的值
第三节 调用函数
知识点:函数调用的规则;函数调用的实际作用是使用函数;
重要程度:★★★★★
调用函数实际上就是使用函数,调用一次就是使用一次。每次调用函数的时候,可以给函数传递不同的数值,得到不同的运行结果。
调用某些函数,可以求得函数值或者完成一些流程(如打印)的功能。
1、函数的调用形式
函数调用的一般形式为: 函数名(实际参数表)
例1:一个具体的调用例子
int add(int x,int y)
{ int z ;
z=x+y ;
return z ;
}
main()
{ int sum;
sum=add(5,6);
printf(“sum=%d”,sum);
}
例1中:有两个函数,一个是main函数,也就是主函数。另一个是add函数,是用来处理两个数相加的。
说明:
1) 在main函数中,add(5,6);就称为函数的调用。可以看到函数调用时,与定义不同。不用写返回值类型和实际参数(简称“实参”)类型。函数add括号中5,6就是实际参数(它们有实际的意义)。
2)实参可以是常量、变量、表达式,甚至是函数的调用(函数值)。所以这个地方
实参为常量: sum=add(5,6);合法调用。
实参为变量: sum=add(x,6);假定x给了一个初始数值5,也是合法调用。
实参为表达式: sum=add(x+y,6);只要x+y可得一个结果且类型为整型,也是合法调用。
实参为函数的返回数值:sum=add(add(5,6),6);由于add(5,6)可以得到一个结果11,所以也是合法调用。(近几次考试重点)
3)函数的调用可以作为一条独立的语句。add(5,6)这个函数调用有返回值时,函数调用可以作为一个表达式出现在任何合法的地方。如果add(5,6)这个调用函数无返回值(即返回值类型为void)时,不能把函数调用的结果通过赋值号进行赋值:sum=add(5,6)就错了,因为add(5,6)函数调用就没有运算的结果,无法给变量sum赋值。
下面通过几个例子来具体学习函数的调用:
例2:与数学式子 对应的C语言表达式是
A) 3*x^n(2*x-1) B) 3*x**n(2*x-1)
C) 3*pow(x,n)*(1/(2*x-1)) D) 3*pow(n,x)/(2*x-1)
分析:本题考察点:库函数的调用。^只是按位异或。x^n显然不是xn ,A显然是错误的。C语言中没有乘方的符号,xn要通过C语言的库函数来完成的。处理乘方的库函数是pow(x,n)。注意参数的先后次序。D选项错误地传递了参数,返回值为nx。B选项中没有“**”这种运算符号,错误。C选项正确的使用了库函数pow(),实参x和n正确的传入,返回值为xn。答案为C。
例3: 以下函数定义:
void fun( int n, double x) { …… }
若以下选项中的变量都已正确定义并赋值,则对函数fun的正确调用语句是
A) fun(int y,double m); B) k=fun(10,12.5);
C) fun(x,n); D) void fun(n,x);
分析:本题考察点:调用函数的语法规则。观察函数的首部,注意到fun函数返回类型为void,表示没有返回值。第一个形参类型为int,第二个形参类型为double。A项调用函数时写出实际参数类型,这个是错误的。B选项fun(10,12.5)是没有运算结果的,是无返回值。那么调用时不能赋值给变量k的。D项调用函数时不需写出返回值类型void。C选项形参与实参的同名不互相影响,是正确的。
例4:本题是2006年9月的考题。以下程序中,函数fun的功能是计算x2-2x+6,主函数中将调用fun函数计算:
y1=(x+8)2-2(x+8)+6
y2=sin2(x)-2sin(x)+6
请填空。
#include "math.h"
double fun(double x) { return(x*x-2*x+6);}
main( )
{ double x,y1,y2;
printf("Enter x: "); scanf("%lf",&x);
y1=fun( );
y2=fun( );
printf("y1=%lf,y2=%lf ",y1,y2);
}
分析:考察点:函数调用中实参与形参之间的传递。题目要求中有两个多项式的计算,实际上是多项式x2-2x+6的x取两次不同的数值来运算。也就是在C语言中两次调用函数,每次调用传递不同实参的问题。可知函数fun返回值为double类型。变量y1实际上存放当形参x为x+8时fun函数的计算结果。变量y2实际上存放形参x为sin(x)时fun函数的计算结果。因此,只需在两次调用fun函数的时候写出正确的实参就可以了。整个程序是实现了从键盘输入x的值,即达到了输出y1与y2值的功能。第一空填x+8,第二空填sin(x)。
第四节 函数的声明
知识点: 函数声明合法的几种表示方式;
重要程度:★★★★
我们知道,每个人都是先起名字,才可以称呼其人。函数也是这样,一般情况下,函数应遵循“先定义后调用”的规则。当然,很多时候都把函数的定义统统放在主函数main的后面,即定义在调用之后。这样做,也可以。但必须是在调用之前对函数进行声明。声明是表示有这样的一个函数存在。
1、函数声明的一般形式
(函数声明必要的是函数名、参数个数、参数的类型、返回值的类型这四样,其中特别记住,函数声明中函数的参数的名字是可以变化甚至不写的!!!)
一个简单的例子
double recarea( double x, double y); /*函数声明*/
main( )
{ double area;
area=recarea(2.2,3.3); /*函数调用*/
printf("area=%d",z);
}
double area( double x, double y) /*函数定义*/
{ double area;
area=x*y;
return area;}
针对该例,我们写出几种合法的函数声明,
写法一:double recarea( double x, double y); 这个和我们后面函数定义的第一部分一模一样。
写法二:double recarea( double , double ); 声明的时候,可以省略形式参数。
写法三:double recarea( double a, double y); 声明的时候,参数的名称可以和后面定义时候不同。
在使用函数时,可以有三种方式:
(1)先定义后调用。此时不需要进行函数声明。
(2)先声明,后调用,最后定义,就是上面例子中采用的方式。
(3)对于返回类型是int类型的,可以先调用,后定义。不需要声明。
有难度的考题;(含有指针的函数声明)
int *max(int *x , int *y)
{if(*x>*y)return x;
else return y;}
这种函数的声明的方法:
1、 int *max(int *x , int *y) 这个是与定义一样的声明。
2、 int *max(int * , int *) 这个是省略了变量的声明。
3、 int *max(int *b , int *a)这个是改变了变量的声明。
2、函数声明的位置
函数声明的位置有两种方式:
1)在函数的外部:那么只要出现了函数的声明,从声明之后的任何位置都可以调用该函数。
2)在某函数的内部:此时的函数声明就有使用范围了。函数的调用只能在函数声明出现的地方。其它函数中是不能调用该函数的。
例1: 若程序中定义了以下函数
float add(float a, float b)
{ float c;
c=a+b;
return c;}
并将其放在调用语句之后,则在调用之前应进行函数声明,以下选项中错误的是
A) float add(float a, b); B) float add(float, float);
C) float add(float b, float a); D) float add(float x, float y);
分析:本题考察点:在函数声明的三种形式。A选项缺少第二个参数的类型名。答案选择A。
例2:本题是2006年4月的考题,若各选项中所用变量已正确定义,函数fun中通过return语句返回一个函数值, 以下选项中错误的程序是
A) main( ) B) float fun(int a,int b){……}
{ …… x=fun(2,10); …… } main( )
float fun(int a,int b){ …… } { …… x=fun(i,j); …… }
C) float fun(int,int); D) main( )
main( ) { float fun(int i,int j);
{ …… x=fun(2,10); …… } x=fun(i,j); …… }
float fun(int a,int b){ …… } float fun(int a,int b){ …… }
分析:在函数的定义、调用和声明。A没有声明就调用函数了,A选项错误。D是在函数体内声明,然后调用。B和C都是在函数外面声明,再在声明之后调用。
函数是一段可以重复使用的代码,用来独立地完成某个功能,它可以接收用户传递的数据,也可以不接收。
无参函数的定义
如果函数不接收用户传递的数据,那么定义时可以不带参数。如下所示:
返回值类型 函数名(){
函数体
}
说明:
- 返回值类型可以是C语言中的任意数据类型,例如 int、float、char 等。
- 函数名是标识符的一种,命名规则和标识符相同。函数名后面的括号
( )
不能少。 - 函数体是函数需要执行的代码。即使只有一个语句,也要由
{ }
包围。 - 在函数体中使用return语句返回数据。
例如,定义一个函数,计算1加到100的结果:
- int sum(){
- int i, sum=0;
- for(i=1; i<=100; i++){
- sum+=i;
- }
- return sum;
- }
计算结果保存在变量sum
中,通过return
语句返回。sum为int
型,所以返回值类型也必须为int
,要一一对应。return
是C语言中的一个关键字,只能用在函数中,用来返回处理结果。
将上面的代码补充完整:
- #include <stdio.h>
- int sum(){
- int i, sum=0;
- for(i=1; i<=100; i++){
- sum+=i;
- }
- return sum;
- }
- int main()
- {
- int a = sum();
- printf("The sum is %d ", a);
- return 0;
- }
运行结果:
The sum is 5050
函数不能嵌套定义,main 也是一个函数定义,要将 sum 放在 main 外面。函数必须先定义后使用,所以 sum 只能在 main 前面。
注意:main 是函数定义,不是函数调用。当可执行文件加载到内存后,系统从 main 函数开始执行,也就是说,系统会调用我们定义的 main 函数。
无返回值函数
有的函数不需要有返回值,或者返回值类型不确定(很少见),那么用void表示,例如:
- void hello(){
- printf ("Hello,world ");
- //没有返回值就不需要 return 语句
- }
void
是C语言中的一个关键字,表示空类型或无类型,绝大部分情况下也就意味着没有 return 语句。
有参函数的定义
如果函数需要接收用户传递的数据,那么定义时就要带参数。如下所示:
返回值类型 函数名(参数列表){
函数体
}
用户数据通过“参数列表”传递给函数,供函数处理。例如,定义一个函数求两个数中的最大值:
- int max(int a, int b){
- if (a>b){
- return a;
- }else{
- return b;
- }
- }
参数(Parameter)本质上也是变量,定义时要指明参数类型和参数名称。参数列表中可以定义一个或多个参数,多个参数之间用逗号,
分隔。参数列表中给出的参数可以在函数体中使用。
调用 max() 函数时可以直接传递整数:
int n = max(10, 20);
也可以传递变量:
int a = 10, b = 20; int n = max(a, b);
也可以整数和变量一起传递:
int a = 10; int n = max(a, 20);
变量 n 得到的值都是20。
函数定义时给出的参数称为形式参数,简称形参;函数调用时给出的参数(传递的数据)称为实际参数,简称实参。函数调用时,将实参的值传递给形参,相当于一次赋值操作。注意:实参和形参的类型、数目必须一致。
将上面的代码补充完整:
- #include <stdio.h>
- int max(int a, int b){
- if (a>b){
- return a;
- }else{
- return b;
- }
- }
- int main(){
- int num1, num2, maxVal;
- printf("Input two numbers: ");
- scanf("%d %d", &num1, &num2);
- maxVal = max(num1, num2);
- printf("The max number: %d ", maxVal);
- return 0;
- }
运行结果:
Input two numbers: 100 200
The max number: 200
定义max时,变量a、b的值都是未知的;调用max时,分别将num1、num2的值传递给a、b,类似于:
a=num1; b=num2;
return 语句可以有多个,可以在函数体的任意位置。在max中,根据 if 的判断结果来执行不同的 return 语句。
函数一旦遇到 return 语句就返回(停止执行),后面的所有语句都不会被执行到,例如:
- int max(int a, int b){
- int n = (a>b) ? a : b;
- return n;
- printf("Function is performed ");
- }
第4行代码是多余的,永远没有执行的机会。
如果把函数比喻成一台机器,那么参数就是原材料,返回值就是最终产品;函数的作用就是根据不同的参数产生不同的返回值。
函数的参数
在函数定义中出现的参数可以看做是一个占位符,它没有数据,只能等到函数被调用时接收传递进来的数据,所以称为形式参数,简称形参。
函数被调用时给出的参数包含了实实在在的数据,会被函数内部的代码使用,所以称为实际参数,简称实参。
形参和实参的功能是作数据传送,发生函数调用时,实参的值会传送给形参。
形参和实参有以下几个特点:
1) 形参变量只有在函数被调用时才会分配内存,调用结束后,立刻释放内存,所以形参变量只有在函数内部有效,不能在函数外部使用。
2) 实参可以是常量、变量、表达式、函数等,无论实参是何种类型的数据,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参,所以应该提前用赋值、输入等办法使实参获得确定值。
3) 实参和形参在数量上、类型上、顺序上必须严格一致,否则会发生“类型不匹配”的错误。
函数调用中发生的数据传送是单向的,只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。 因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。
【示例】计算 1+2+3+...+(n-1)+n 的值。
- #include <stdio.h>
- int sum(int n){
- int i;
- for(i=n-1; i>=1; i--){
- n+=i;
- }
- printf("The inner n = %d ",n);
- return n;
- }
- int main(){
- int m, total;
- printf("Input a number: ");
- scanf("%d", &m);
- total = sum(m);
- printf("The outer m = %d ", m);
- printf("1+2+3+...+%d+%d = %d ", m-1, m, total);
- return 0;
- }
运行结果:
Input a number: 100↙
The inner n = 5050
The outer m = 100
1+2+3+...+99+100 = 5050
通过 scanf 输入 m 的值,作为实参,在调用 sum 时传送给形参 n。
从运行情况看,输入 m 值为100,即实参 m 的值为100,把这个值传给函数 sum 时,形参 n 的初值也为100,在函数执行过程中,形参 n 的值变为 5050。函数运行结束后,输出实参 m 的值仍为100,可见实参的值不随形参的变化而变化。
函数的返回值
函数的返回值是指函数被调用之后,执行函数体中的程序段所取得的值,可以通过return
语句返回。
return语句的一般形式为:
return 表达式;
或者:
return (表达式);
例如:
return max; return a+b; return (100+200);
函数中可以有多个 return 语句,但每次调用只能有一个return 语句被执行,所以只有一个返回值。
一旦遇到 return 语句,不管后面有没有代码,函数立即运行结束,将值返回。例如:
- int func(){
- int a=100, b=200, c;
- return a+b;
- return a*b;
- return b/a;
- }
返回值始终 a+b 的值,也就是300。
没有返回值的函数为空类型,用void
进行说明。例如:
- void func(){
- printf("Hello world! ");
- }
一旦函数的返回值类型被定义为 void,就不能再接收它的值了。例如,下面的语句是错误的:
int a = func();
为了使程序有良好的可读性并减少出错, 凡不要求返回值的函数都应定义为 void 类型。