首页 上页 下页 节 末页 结束
第七章 函数
,C语言程序设计,
课程讲义
2006年 4月
首页 上页 下页 节 末页 结束
上一章节课程回顾
数组的基本概念
一维数组的定义和引用
二维数组的定义和引用
字符数组

首页 上页 下页 节 末页 结束
7.1 概述
7.2 函数定义的一般形式
7.3 函数参数和函数的值
7.4 数组作为函数参数
7.5 函数的嵌套调用和递归调用
7.6 全局变量和局部变量
7.7 变量的存储属性
第 7章 函数

首页 上页 下页 节 末页 结束
本次课主要内容
重点,
一、重点掌握函数的定义、声明及传值
与调用。
二,熟悉函数 的嵌套与递归调用。
三、掌握变量的作用域与存储类别
难点,
一、形参与实参之间的值传递
二、函数的嵌 套与递归调用
本章主要
内容
首页 上页 下页 节 末页 结束
函数
一、函数
C语言中,程序是由函数来实现的。函数可分为( 1):
标准库函数( 2)用户自定义函数。
在 C语言中,至少要有一个 main ( )函数,程序的执行是
从 main( )函数开始的,也是由主函数结束的。函数的
调用过程如图,f11( )
{…}
f21( )
{…}
f31( )
{…}
f1( )
{…
f11( );
…}
f2( )
{…
f11( );
f22( );
…}
main( )
{…
f1( );

f2( );
…}
首页 上页 下页 节 末页 结束
7.1函数的概述
其中,每个方框相当于一个模块,而每个函数相当于一
个输入输出系统。 in out
例如:要设计一个如下图所示的管理程序,
高等院校事务管理





























首页 上页 下页 节 末页 结束
花括弧内是函数
体,它包括声明
和语句部分
8.2 函数定义的一般形式
一、函数的 定义 与 声明
1、定义,[存储类型 ] [数据类型 ] 函数名(带类型的
形表)
{声明部分
语句
}
例如,int max(int x,int y)
{int z;
z=x>y?x:y;
return(z);
}
Return(z)的作用是将 z的值
作为函数值带回到主调函
数中。在函数定义时已指
定函数 max函数为整型,在
函数体中定义了 z为整型,
两者类型一致,将 z作为函
数 max的值带回调用函数。
首页 上页 下页 节 末页 结束
8.2 函数定义的一般形式
例 L8-2-1.C:计算表达式的值
x 2- x+1 (x<0)
x3+x+3 (x>0)
float y (float x )
{ if (x<0)
return (x*x- x+1);
else
return (x*x*x+x+3);
}
注意:当有多个 return语句时,每个 return语句后
面的表达式的类型应相同。
y={
首页 上页 下页 节 末页 结束
8.2 函数定义的一般形式
如,func (int n)
{ if (n>10)
return (2*x+3);
else
return;
} 编译时,由于第二个 return语句而给出警告。
说明,1)存储类型(后面讲)
2)数据类型:指函数返回值的类型。 若缺省函数
类型,一律按整型处理。
3)只有自定义函数而没有 main()函数的程序是没
有意义的。(例 L8—2-1)
首页 上页 下页 节 末页 结束
8.2 函数定义的一般形式
2、函数的 声明
[数据类型 ] 函数名 (类型标记符 [形参 ], … );
注意后面的“;”不要丢了。它与定义不同,一个函数一般要经过声明
才能使用(就好象变量一样必须先声明才能使用),除非它在调用函
数( main函数)的前面定义。 只有当返回的数据类型为 int,数据类
型才可省略。
如,main( )
{ …
double new_style ( int,double ); /*函数声明 */

}
Double new_style (int a,double x) /*函数定义 */
{

}
函数声明
后面有,;”
函数定义后面
没有,;”
首页 上页 下页 节 末页 结束
8.3函数参数和函数的值
一、关于形参和实参的说明,
1、形参只有当调用时才临时分配存储元。
2、实参一定要有确定的值,可以是表式。
3、实参和形参的类型应相同或赋值相容,并
且实参的个数与形参的个数一致。
参数的传递是通过调用来完成的,
分为按值传递和按址传递。
首页 上页 下页 节 末页 结束
8.3函数参数和函数的值
二、函数的返回( return 语句)
return 返回值表达式;
return后面表达式的类型必须和函数定义时函
数名前的类型保持一致。
return语句有三种形式,
1,return; (没有返回值 )
2,return 表达式;
3,return (表达式 );
首页 上页 下页 节 末页 结束
三、函数的调用
函数名 ( [实参表 ]);( 如果是有返回
值的函数,则可将调用结果赋值给别的
变量,若是无值函数,则不能赋值,只
能单独调用;)
四、形参、实参、参数的传递
形参:定义函数的参数。
实参:调用函数时有具体值的参数。
首页 上页 下页 节 末页 结束
8.3函数参数和函数的值
例 L8_3_1.c
main( )
{ int a=3,b=5;
void swap( int,int ); (函数申
明)
swap (a,b);
printf(“a=%d,b=%d\n”,a,b);
}
void swap (int x,int y)
{ int temp;
temp=x; x=y; y=temp;
printf(“x=%d,y=%d \n”,x,y);
}
是按值传递的
按址传递放在指针里面讲。
Main()函数,
调用 Swap函数
传递值
3
5
a
b
3
5
x
y
3
temp 程序运行结果,
x=5,y=3
a=3,b=5
首页 上页 下页 节 末页 结束
函数调用
函数声明
函数定义,其位置可以
在 main()前,这样可以
省略函数申明。也可以
在 main()后。
Main()
{ float x,y;
float y(float);
scanf(“%f”,&x);
Printf(“y=%8.2f\n”,y(x));
}
float y (float x )
{ if (x<0)
return (x*x- x+1);
else
return (x*x*x+x+3);
}
首页 上页 下页 节 末页 结束
实参为数组
元素
#include "stdio.h"
main()
{int a[3],i,m;
int max(int,int);
printf("Please input 3 int:\n");
for(i=0;i<3;i++)
scanf("%d",&a[i]);
m=max(a[0],a[1]);
m=max(m,a[2]);
printf("max=%d\n",m);
}
int max(int a,int b)
{return(a>b?a:b);
}
8.4、数组作为函数参数
? 数组元素和简单变量具有相同的特性,因此可
以作为函数的实参来出现。( L8_4_1)
形参为整形
首页 上页 下页 节 末页 结束
二、数组名作为函数参数
? 有一个一唯数组 score,内放 10个
学生的分数,求平均成绩。
首页 上页 下页 节 末页 结束
形参
实参
#define N 10
main()
{float score[N],avg;
float average(float arr[N]);
int i;
printf("Please input %d score:\n",N);
for(i=0;i<N;i++)
scanf("%f",&score[i]);
avg=average(score);
printf("Average score is %7.2f\n",avg);
}
float average(float arr[N])
{int i;
float sum=0.0,aver;
for(i=0;i<N;i++)
sum=sum+arr[i];
aver=sum/N;
return(aver);
}
形参和实
参都用数
组名
首页 上页 下页 节 末页 结束
数组名作为函数参数
? 实参数组和形参数组类型应保持一致。
? 在被调用函数中声明的数组大小是不起任
何作用的。因为 C编译系统对形参数组大小
不作检查,形参数组名只代表一个地址,
在调用时将实参数组的首地址传到形参数
组名,也就是说,形参数组并不在内存中
重新申请数组的空间,而是和实参数组共
占存储单元。
首页 上页 下页 节 末页 结束
根据需要另设
一个参数传递
需要处理的数
组元素的个数
数组元素要参加处理
的实际个数
#define N 10
main()
{float score[N],avg;
float average(float arr[N]);
int i;
printf("Please input %d score:\n",5);
for(i=0;i<5;i++)
scanf("%f",&score[i]);
avg=average(score,5);
printf("Average score is %7.2f\n",avg);
}
float average(float arr[],int n)
{int i;
float sum=0.0,aver;
for(i=0;i<n;i++)
sum=sum+arr[i];
aver=sum/n;
return(aver);
}
首页 上页 下页 节 末页 结束
实参为数组

形参定义二维数
组的维数及每一
维的大小,可以
缺省第一维的大

#include "stdio.h"
main()
{int a[3][3]={1,1,1,1,1,1,1,1,1};
int s(int aa[][3]);
clrscr();
printf("sum=%d\n",s(a));
}
int s(int a[][3])
{int sum=0;
int i,j;
for(i=0;i<3;i++)
for(j=0;j<3;j++)
if(i==j||i+j==2) sum+=a[i][j];
return(sum);
}
首页 上页 下页 节 末页 结束
嵌套与递归调用,
嵌套调用:在调用一个函数的过程中又调用另一个函数。
递归调用:一个函数直接或间接地调用本身。
例 L8_5_1.c 求 n!的值
#include,stdio.h”
long factor ( int );
main( )
{ int i;
scanf(“%d,,&i);
printf(“%d != % ld \n”,i,factor(i));
}
8.5函数的嵌套调用和递归调用
首页 上页 下页 节 末页 结束
函数
long factor (int x)
{ if (x==1 | | x==0) retur(1);
else
return ( x*factor( x- 1));
}
调用 factor(4)
Main()函
数 Factor(4)
求 4*factor(3)
Factor(3)
求 3*factor(2)
Factor(2)
求 2*factor(1)
Factor(1)
…….,
返回值 1
返回值 2 返回值 6 返回值
24
输出
Factor(5)=24
程序中不应出现无终止的递归
调用,用 if语句来控制,只有
在某一条件成立时才继续执行
递归调用,否则就不再继续。
首页 上页 下页 节 末页 结束
a,b的有效范围
C的有效范围
8.6全局变量和局部变量
1、全局变量,
是在函数之外定义的变量,它的有效范围是从定义它的
地方开始,到整个程序结束的任何地方。
2、局部变量,
在一个函数内定义的变量,只在本函数内有效,这种变
量就是局部变量。
Main()
{int a,b;
… …
{int c;
c=a+b;
… …
}
… …
}
首页 上页 下页 节 末页 结束
所以在 main()里不能对变
量 C进行引用。
变量 C是再函数 fun
内部定义的,它就
只再该函数内部有
效。
8.6全局变量和局部变量
fun(int a,int b)
{int c;
c=a>b?a:b;
return c;
}
main()
{int a=7,b=10;
fun(a,b);
printf("max=%d\n",d);
}
int d;
d=fun(a,b);
首页 上页 下页 节 末页 结束
在函数 fun()中,虽然没有
定义变量 a,b,但由于它
们定义在程序的最前面,
是全程变量,凡是在定义
该变量的后面定义的函数
均可以引用它们。
8.6全局变量和局部变量
#include,stdio.h”
int a=3,b=5; /*在函数体外定义的变量 */
Main( )
{ void fun( );
printf(,a= %d,b=%d \n,,a,b);
fun ( );
printf(,a= %d,b=%d \n,,a,b);
}
void fun (void)
{
int c ;
c=a;
a=b;
b=c;
}
例 L8_6_1.c 交换两个变量的值 变量 a,b是
外部变量
首页 上页 下页 节 末页 结束
8.6全局变量和局部变量
2、用 extern声明外部变量,用以扩充外部变量的作用域。
( 1)在一个文件内声明外部变量:如,L8_6_1
main( )

void gx( )

int x,y;
void gy( )

还可用它在不同的程序中使用,如 在 file1.c 中引用 file2.c中定义的
变量 x,y。
extern int x,y;
x,y原作用域
x,y新的作用域
首页 上页 下页 节 末页 结束
8.7变量的存储属性
变量的存储类型有,
register型:寄存器类型
auto 型:自动型(缺省的都是 auto型)
static 型:静态型
一、自动变量
[auto] 数据类型 变量名 [=初值表达式 ], … ;
不作特殊说明的变量都是自动变量 。它用之则建、
用完即撤,仅在函数体内或复合语句内建立和有
效,存储在内存的动态数据区中。 例 L8_7_1.c
首页 上页 下页 节 末页 结束
程序一进入 main()函
数,变量 x就被创建,
当程序运行到此局部
范围内(即花括号内)
时创建,用完即撤消,
即释放变量。
当程序运行到函数 prt()
内部时,变量 x才被创建,
离开函数时,就被撤消
main( )
{int x=1;
clrscr();
{ void prt(void);
int x=3;
prt( );
printf("x=%d\n",x);
}
printf("%d\n",x);
}
void prt(void)
{
int x=5;
printf("%d\n",x);
} 总之,auto变量是局部变量,在赋值之前,其值是不确定的,
首页 上页 下页 节 末页 结束
8.7变量的存储属性
二,register变量(寄存器变量)
与 auto变量完全相同,只是速度快,存储在 CPU的寄存器中。
#include,stdio.h”
void m_table(void)
{ register int i,j;
for (i=1 ; i<=9 ; i++)
for (j=1 ; j<=i ; j++)
{ printf(“%d * %d =%d,,j,i,j*i);
putchar (( I==j)? ? \n ?, ? \t ? );
}
}
Main()
{ void m_table( );
m_table( );
}
首页 上页 下页 节 末页 结束
8.7变量的存储属性
三,static 变量(静态变量)
auto变量是在程序运行过程中建立的,是动态建立、动
态撤消。而 静态变量是在程序一开始就建立的,不撤
消直到程序结束。因而其值具有可继承性,但它只能
在本 程序 内使用。
结果为,1,2,3
一般需要保留函数上一次的调用结果时,就定义成静态变量
Void incr(void)
{
static int x=0;
x++;
printf(“%d \n,,x );
}
例 L8-7-2.c
main( )
{ void incr(void);
incr( );
incr( );
incr( );
}
首页 上页 下页 节 末页 结束
上一次的结
果,即 n-1的
阶乘
对静态局部变量赋初值
时在编译时进行的,也
就是整个程序的运行过
程中,它已经有初值,
以后每次调用函数时不
再重新赋初值而保留了
上一次的运行结果。
Static变量
? 例 8-7-3.c:打印 1到 5的阶乘

int fac(int n)
{static int f=1;
f=f*n;
return(f);
}
main()
{int i;
for(i=1;i<=5;i++)
printf("%d!=%d\n",i,fac(i));
}
首页 上页 下页 节 末页 结束
#include "stdio.h"
int x,y;
one()
{int a,b;
a=25,b=10;
x=a-b;
y=a+b;
return;
}
main()
{int a,b;
a=9,b=5;
x=a+b;
y=a-b;
one();
printf("%d,%d\n",x,y);
}
x,y是全局变量
a,b是局部变量,只
在 one函数体内有效
运行结果,
15,35
a,b是只在 main函数内
有效的局部变量
首页 上页 下页 节 末页 结束
#include "stdio.h"
int x,y;
two()
{int a=25,b=10;
int x,y;
a=25,b=10;
x=a-b;
y=a+b;
return;
}
main()
{int a=9,b=5;
x=a+b;
y=a-b;
two();
printf("%d,%d\n",x,y);
}
x,y是全局变量
a,b,x,y是局部变量。
在 two函数体内有

a,b,x,y是在 main()内
有效的局部变量
运行结果,
14,4
首页 上页 下页 节 末页 结束
#include "stdio.h"
three()
{extern int x,y;
int a=25,b=10;
x=a-b;
y=a+b;
return;
}
int x,y;
main()
{int a=9,b=5;
x=a+b;
y=a-b;
three();
printf("%d,%d\n",x,y);
}
运行结果,
15,35
首页 上页 下页 节 末页 结束
一个较大的程序一般应分为若干个程序模块,每一个模
块用来实现一个特定的功能。一个 C程序可由一个主函数
和若干个函数构成。由主函数调用其他函数,其他函数也
可以互相调用。同一个函数可以被一个或多个函数调用多
次。要正确使用程序,一定要了解函数的正确使用。即掌

1、函数的一般定义、以及形式参数与实参之间的值
的传递。
2、函数的调用,以及函数的嵌套调用与递归调用。
本章小结
首页 上页 下页 节 末页 结束
在 C语言函数的定义和引用中,以下描述正确的是 ____
A,必须有形式参数
B,也可以没有形式参数
C,数组名不能作为形式参数
D,形式参数必须是变量名
本题考核了函数的定义形式。正确答案是 B。
课堂同步,做做与练练
【 练 8.1】
试题分析
选择正确的选项,
首页 上页 下页 节 末页 结束
C语言规定,函数返回值的类型是由 _______决定的
A.return语句中的表达式类型
B,调用该函数时的主调函数类型
C.调用该函数时由系统临时
D.在定义函数时所指定的函数类型
本题考核了函数定义时函数类型。正确答案是 D。
课堂同步,做做与练练
【 练 8.2】
试题分析
选择正确的选项,
首页 上页 下页 节 末页 结束
课堂同步,课后练习与作业
1、编写一个函数,判断任一整数是否为素数,用
main()函数调用并测试之 。
2、用递归方法求 n! 。