制 作:方 斌
C语言程序设计教程郧阳师范高等专科学校计算机科学系方 斌 制作制 作:方 斌第 7章 函数
C语言是通过函数来实现模块化程序设计的 。
所以较大的 C语言应用程序,往往是由多个函数组成的,每个函数分别对应各自的功能模块 。
制 作:方 斌
【 例 】 编写一个儿童算术能力测试软件显示软件封面检查密码产生题目接受回答评判计分显示结果如果要继续练习告别词
main()
{ char ans ='y';
clrscr();
cover(); /*调用软件封面显示函数 */
password(); /*调用密码检查函数 */
while (ans ==’y’|| ans ==’Y’)
{ question(); /*调用产生题目函数 */
answers(); /*调用接受回答函数 */
marks(); /*调用评分函数 */
results(); /*调用结果显示函数 */
printf(“是否继续练习? (Y/N)\n”);
ans=getch (); }
printf(“谢谢使用,再见!” );
}
制 作:方 斌
/*定义所用函数 */
cover() {…} /* 软件封面显示函数 */
password() {…} /* 密码检查函数 */
question() {…} /* 产生题目函数 */
answers() {…} /* 接受回答函数 */
marks() {…} /* 评分函数 */
results() {…} /* 结果显示函数 */
制 作:方 斌
7.1 库函数
库函数不需要用户自己来定义和编写代码,使用的时候只需要加上相应的头文件即可。如我们前面用过的求平方根函数 sqrt()和求实数绝对值函数 fabs()都是库函数,使用时只需要加上包含这个库函数的头文件” math.h”即可。
C语言提供的库函数请参考附录 5
制 作:方 斌函数使用常识:
1,C程序执行总是从 main函数开始,调用其它函数后总是回到 main函数,最后在 main函数中结束整个程序的运行。
2、一个 C程序由一个或多个源(程序)文件组成 ——可分别编写、编译和调试。
3、一个源文件由一个或多个函数组成,可为多个 C程序公用。
4,C语言是以源文件为单位而不以函数为单位进行编译的。
5、所有函数都是平行的、互相独立的,即在一个函数内只能调用其他函数,不能再定义一个函数(嵌套定义)。
6、一个函数可以调用其他函数或其本身,但任何函数均不可调用 main函数。
制 作:方 斌
7.2 函数的定义和返回值
7.2.1 函数定义格式:
函数返回值类型 函数名 (形参类型 1 形参名 1,形参类型 2 形参名 2,… )
{
函数体语句 ;
}
说明:
如果省略 函数返回值类型 则系统默认为 函数返回值类型 为 int类型如果函数没有返回值,则声明 函数返回值类型 为 void类型注意这里必须没有分号 (;)
制 作:方 斌函数定义实例
double add (double a,double b)
{
double s;
s = a + b;
return s;
}
函数返回值类型函数名形参表函数体语句函数的返回值,其类型必须与定义的返回值类型一致注意这里必须没有分号 (;)
制 作:方 斌
7.2.2 函数的返回值
如果定义的函数有返回值(即返回值不为
void),则在函数体语句中必须用 return语句返回一个值,其类型必须与定义的函数返回值类型一致。如果不一致,则系统会进行隐式的强制类型转换。其格式如下:
return 表达式 ;
或者:
return (表达式 );
制 作:方 斌
如果定义的函数返回值为 void,则不能用
return语句返回一个值。
return后面也可以不跟表达式,这时它的作用只是使程序的执行流程返回到调用处。
函数体中可以有多个 return语句,但程序只会执行其中的一个。
制 作:方 斌返回值数据类型 函数名 ()
{
函数体语句 ;
}
无参函数定义格式或者:
返回值数据类型 函数名 (void)
{
函数体语句 ;
}
制 作:方 斌无返回值也无形式参数函数的定义
void 函数名 ()
{
函数体语句 ;
}
无返回值函数定义格式或者:
void 函数名 (void)
{
函数体语句 ;
}
制 作:方 斌无返回值但有形式参数函数的定义
void 函数名 (形式参数表 )
{
函数体语句 ;
}
无返回值函数定义格式或者:
void 函数名 (形式参数表 )
{
函数体语句 ;
}
制 作:方 斌
7.4 函数的声明
除主函数 main()之外,对于用户自定义的函数都必须遵循“先定义,后使用”的原则。即在调用函数的位置之前必须就有该函数的定义,
否则,就必须在调用之前对函数进行声明(或称为函数原型的说明),通常情况下我们都这样做的。
制 作:方 斌
7.4.1 函数声明的格式
函数返回值类型 函数名 (形参类型 1,形参类型 2,… );
如:
double add(double,double);
因为函数的声明是一条语句,
所以末尾必须有分号注意这里必须有分号 (;)
制 作:方 斌
7.5 调用函数与被调用函数之间的数据传递
调用函数与被调用函数之间的数据有三种方式进行传递
1、实际参数和形式参数之间的数据传递
2、函数通过 return语句把一个值返回给调用函数
3、通过全局变量(不提倡)
制 作:方 斌
函数的参数分为 形参 和 实参 两种,作用是实现数据传送。
形参出现在函数定义中,只能在该函数体内使用。发生函数调用时,调用函数把实参的值复制一份,传送给被调用函数的形参,从而实现调用函数向被调用函数的数据传送。
制 作:方 斌函数定义、声明和调用实例
[案例 7.1] 定义一个函数,用于求两个数中的大数。
int max(int n1,int n2) /*定义一个函数 max()*/
{
return (n1>n2?n1:n2);
}
void main()
{
int max(int,int); /*函数声明,在此可以省略 */
int num1,num2;
printf("input two numbers:\n");
scanf("%d%d",&num1,&num2);
printf("max=%d\n",max(num1,num2));
}
制 作:方 斌函数实例:数据传递(值传递)
void try(int,int,int);
void main()
{
int x = 2,y = 3,z = 0;
printf("(1) x = %d,y = %d,z = %d\n",x,y,z);
try(x,y,z);
printf("(4) x = %d,y = %d,z = %d\n",x,y,z);
}
制 作:方 斌
void try(int x,int y,int z)
{
printf("(2) x = %d,y = %d,z = %d\n",x,y,z);
z = x + y;
x = x * x;
y = y * y;
printf("(3) x = %d,y = %d,z = %d\n",x,y,z);
}
制 作:方 斌程序实例:以下程序试图通过调用 swap函数交换两个变量的值
void swap(int,int);
void main()
{
int a = 10,b = 20;
printf("(1)a = %d,b = %d\n",x,y);
swap(a,b);
printf("(4)a = %d,b = %d\n",x,y);
}
制 作:方 斌
void swap(int x,int y)
{
int t;
printf("(2)x = %d,y = %d\n",a,b);
t = x;
x = y;
y = t;
printf("(3)x = %d,y = %d\n",a,b);
}
制 作:方 斌分析
10a 20b
10x 20y
10a 20b
20x 10y
a=10,b=20分别传值给形式参数 x,y,则形式参数的值 x=10,y=20。
若在 swap()函数中交换了形式参数 x,y的值,但实参 a,b的值不变。
制 作:方 斌
[案例 ] 实参对形参的数据传递。
/*实参对形参的数据传递。 */
void main()
{
void s(int n); /*说明函数 */
int n=100; /*定义实参 n,并初始化 */
s(n); /*调用函数 */
printf(“n_s=%d\n”,n); /*输出调用后实参的值 (100),便于进行比较 */
}
制 作:方 斌
void s(int n) /*函数定义 */
{
int i;
printf(“n_x=%d\n”,n); /*输出改变前形参的值,100*/
for(i=n-1; i>=1; i--) n--; /*改变形参的值 */
printf(“n_x=%d\n”,n); /*输出改变后形参的值,1*/
}
制 作:方 斌说明:
函数定义不允许嵌套 。
在C语言中,所有函数(包括主函数 main())
都是平行的。一个函数的定义,可以放在程序中的任意位置,主函数 main()之前或之后。但在一个函数的函数体内,不能再定义另一个函数,即不能嵌套定义。
制 作:方 斌
空函数 ──既无参数、函数体又为空的函数。
其一般形式为:
[函数类型 ] 函数名 (void)
{
}
制 作:方 斌程序实例
main()
{
max(float,float); /*函数声明 */
float a=1.5,b=2.5;
int c;
c = max(a,b);
printf(“max is %d\n”,c);
}
制 作:方 斌
max(float x,float y) /*用“值传递”分析法进行变量跟踪 */
{
float z;
z = x > y? x,y;
return z;
} 程序运行结果:
max is 2
(编译通过,结果错误)
制 作:方 斌补充说明:
实参可以是常量、变量、表达式、函数等。无论实参是何种类型的量,进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。因此,应预先用赋值、输入等办法,使实参获得确定的值。
形参变量只有在被调用时,才分配内存单元;
调用结束时,即刻释放所分配的内存单元。因此,形参只在该函数内有效。调用结束,返回到调用函数后,则不能再使用该形参变量。
制 作:方 斌
实参和形参占用不同的内存单元,即使同名也互不影响。
实参与形参的数据类型应相同或赋值兼容。
实参对形参的数据传送是单向的,即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。在内存中,实参单元和形参单元占有不同的单元。
制 作:方 斌
调用函数时,函数名称必须与具有该功能的自定义函数名称完全一致。
实参在类型上按顺序与形参必须一一对应和匹配。如果类型不匹配,C编译程序将按赋值兼容的规则进行转换。如果实参和形参的类型不赋值兼容,通常并不给出出错信息,且程序仍然继续执行,只是得不到正确的结果。
制 作:方 斌如果实参表中包括多个参数,对实参的求值顺序随系统而异。有的系统按自左向右顺序求实参的值,有的系统则相反。 Turbo C和 MS C是按自右向左的顺序进行的 。
制 作:方 斌
7.6 程序举例
例 7.4 设计一个函数,用来判断一个数是否为素数
设计思路:
1、函数的返回值:
可以利用函数的返回值来判断这个数是否为素数,如果是素数则返回 1,否则返回 0。程序可以根据这个返回值来判断该数是否为素数。
2、形参:
形参即为要判断的数制 作:方 斌函数设计
int IsPrime(int n)
{
int i;
int m = (int)sqrt(n); /*注意程序中用到了库函数 sqrt()*/
for(i = 2; i <= m; i++)
{
if(n % i == 0) return 0;
else return 1;
}
}
制 作:方 斌主程序设计
#include <math.h>
#include<stdio.h>
int IsPrime(int); /*函数声明 */
void main()
{
int x;
printf("Input a integet number:");
scanf("%d",&x);
if(IsPrime(x)) /*函数调用,并把返回值作为 if语句的表达式 */
printf("%d is a prime.\n",x);
else
printf("%d isn't a prime.\n",x);
}
制 作:方 斌例 7.5 设计函数验证任意偶数为两个素数之和并输出这两个素数
判断一个数是否为素数的函数见例 7.4
再设计一个函数完成如下功能:
算法:设要验证的偶数为 x,可依次从 x中减去 i,i 从 2变化到 x/2。
具体算法如下:
1,int i = 2;
2,if(IsPrime(i)) 转到执行步骤 3;
else 转到执行步骤 5;
3,if(IsPrime(x-i)) 转到执行步骤 4;
else 转到执行齢 5;
4,print(x,x-i); return;
5,i++; goto 步骤 2;
制 作:方 斌函数设计
void Even(int x) /*不需要返回值 */
{
int i;
for(i = 2; i <= x/2; i++)
{
if(IsPrime(i)) /*在这个函数中调用另外一个函数 */
{
if(IsPrime(x-i))
{
printf("%d = %d + %d\n",x,i,x-i);
}
}
}
}
制 作:方 斌主程序设计
#include <math.h>
int IsPrime(int);
void Even(int);
void main()
{
int a;
printf("Input a even number:");
scanf("%d",&a);
if(a % 2 == 0)
Even(a);
else
printf("%d isn't a even number.\n",a);
}
制 作:方 斌例 7.6 设计函数 sum(int n)用以求和数作为函数返回值返回。其中 f(x)=x2+1
n
x
xf
0
)(
int sum(int);
int f(int);
void main()
{
int a,b;
printf("Input a integer number:");
scanf("%d",&a);
b = sum(a);
printf("a = %d,sum = %d\n",a,b);
}
制 作:方 斌
int f(int x)
{
return x*x + 1;
}
int sum(int n)
{
int i,s = 0;
for(i = 0; i <= n; i++)
s += f(i);
return s;
}
制 作:方 斌本章作业
7.15 7.16 7.17 7.18
补充:求以下程序的运行结果。
void main()
{
int i=5;
printf("%d\n",sub(i));
}
int sub(int n)
{ int a;
if (n==1) return 1;
a=n+sub(n-1);
return a;
}