你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
1
第六章 函数概述函数的定义函数的返回值函数的调用函数参数及其传递方式函数的嵌套与递归调用变量的存储属性数组作为函数参数你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
2
6.1 概述
模块化程序设计
基本思想:将一个大的程序按功能分割成一些小模块,
特点:
各模块相对独立、功能单一、结构清晰、接口简单
控制了程序设计的复杂性
提高元件的可靠性
缩短开发周期
避免程序开发的重复劳动
易于维护和功能扩充
开发方法,自上向下,逐步分解,分而治之你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
3
源程序文件1
预编译命令说明部分 执行部分函数1 函数n
源程序文件i 源程序文件n
C程序
C程序结构
C是 函数式 语言
必须有且只能有一个名为 main的主函数
C程序的执行总是 从 main函数开始,在 main中结束
函数 不能嵌套定义,可以嵌套调用
C是模块化程序设计语言你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
4
从用户角度
标准函数(库函数):由系统提供
用户自定义函数
从函数形式
无参函数
有参函数使用 库函数 应注意:
1、函数功能
2、函数参数的数目和顺序,及各参数意义和类型
3、函数返回值意义和类型
4、需要使用的包含文件函数分类你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
5
一般格式 合法标识符函数返回值类型缺省 int型无返回值 void
函数体函数类型 函数名 ( 形参类型说明表 )
{
说明部分语句部分
}
现代风格,
例 有参函数(现代风格)
int max(int x,int y)
{ int z;
z=x>y?x:y;
return(z);
}
例 有参函数(现代风格)
int max(int x,y)
{ int z;
z=x>y?x:y;
return(z);
}
例 空函数
dummy( )
{ }
函数体为空例 无参函数
printstar( )
{ printf(“**********\n”); }

printstar(void )
{ printf(“**********\n”); }
6.2 函数的定义你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
6
函数类型 函数名(形参表)
形参类型说明
{
说明部分语句部分
}
传统风格,
例 有参函数(传统风格)
int max(x,y)
int x,y;
{ int z;
z=x>y?x:y;
return(z);
}
函数传统风格和例子你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
7
返回语句
形式,return(表达式 );
或 return 表达式 ;
或 return;
功能:使程序控制从被调用函数返回到调用函数中,
同时把返值带给调用函数
说明:
函数中可有多个 return语句
若无 return语句,遇 }时,自动返回调用函数
若函数类型与 return语句中表达式值的类型不一致,按前者为准,自动转换 ------函数调用转换
void型函数例 无返回值函数
void swap(int x,int y )
{ int temp;
temp=x;
x=y;
y=temp;
}
6.3 函数的返回值你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
8
调用形式函数名 (实参表 );
说明:
实参与形参 个数相等,类型一致,按顺序一一对应
实参表求值顺序,因系统而定( Turbo C 自右向左 )
6.4 函数的调用你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
9
函数语句:
例 printstar();
printf(“Hello,World!\n”);
函数表达式:
例 m=max(a,b)*2;
函数参数:
例 printf(“%d”,max(a,b));
m=max(a,max(b,c));
函数的调用方式你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
10
对被调用函数要求:
必须是 已存在 的函数
库函数,#include <*.h>
用户自定义函数,函数类型说明
函数说明
一般形式,函数类型 函数名 (形参类型 [形参名 ],…,,);
或 函数类型 函数名 ();
作用:告诉编译系统函数类型、参数个数及类型,以便检验
函数定义 与 函数说明 不同
函数说明位置,程序的数据说明部分(函数内或外)
下列情况下,可不作函数说明
若函数返值是 char或 int型,系统自动按 int型处理
被调用函数定义出现在主调函数之前
有些系统 (如 Borland C++)要求函数说明指出函数返值类型和形参类型,并且对 void 和 int 型函数也要进行函数说明函数说明你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
11
形参与实参
形式参数:定义函数时函数名后面括号中的变量名
实际参数:调用函数时函数名后面括号中的表达式
c=max(a,b); ( main 函数)
( max 函数)max(int x,int y)
{ int z;
z=x>y?x:y;
return(z);
}
例 比较两个数并输出大者 main()
{ int a,b,c;
scanf("%d,%d",&a,&b);
c=max(a,b);
printf("Max is %d",c);
}
max(int x,int y)
{ int z;
z=x>y?x:y;
return(z);
}
形参实参
6.5 函数参数及其传递方式你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
12
说明:
实参必须有确定的值形参必须指定类型形参与实参 类型一致,个数相同若形参与实参类型不一致,自动按形参类型转换 —
——函数调用转换形参在函数被调用前不占内存 ;函数调用时为形参分配内存;调用结束,内存释放形参与实参形式参数:定义函数时函数名后面括号中的变量名实际参数:调用函数时函数名后面括号中的表达式
6.5 函数参数及其传递方式你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
13
值传递 方式
方式:函数调用时,为形参分配单元,并将实参的值 复制 到形参中;调用结束,形参单元被释放,实参单元仍保留并维持原值
特点:
形参与实参占用 不同 的内存单元
单向 传递参数传递方式你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
14
7 11x,y:调用前:
调用结束,7 11x,y:
/*ch7_2.c*/
#include <stdio.h>
main()
{ int x=7,y=11;
printf("x=%d,\ty=%d\n",x,y);
printf("swapped:\n");
swap(x,y);
printf("x=%d,\ty=%d\n",x,y);
}
swap(int a,int b)
{ int temp;
temp=a; a=b; b=temp;
}
调用:
7 11a,b:
7 11x,y:
swap,7 11x,y:
11 7a,b:
temp
例 交换两个数你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
15
方式:函数调用时,将数据的 存储地址 作为参数传递给形参
特点:
形参与实参占用 同样 的存储单元
,双向,传递
实参和形参必须是 地址 常量或变量函数的地址传递你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
16
/*ch9_3.c*/
swap(p1,p2)
int *p1,*p2;
{ int p;
p=*p1;
*p1=*p2;
*p2=p;
}
main()
{int a,b;
scanf("%d,%d",&a,&b);
printf(“a=%d,b=%d\n”,a,b);
printf(“swapped:\n”);
swap(&a,&b);
printf(”a=%d,b=%d\n",a,b);
}
例 交换两个数 a
5 9
b调前:
a
5
9
b调 swap:
p1
&a
&b
p2
a
9
5
b交换:
p1
&a
&b
p2
a
9 5
b返回:
例子图解你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
17
#include <stdio.h>
long sum(int a,int b);
long factorial(int n);
main()
{ int n1,n2;
long a;
scanf("%d,%d",&n1,&n2);
a=sum(n1,n2);
printf("a=%1d",a);
}
long sum(int a,int b)
{
long c1,c2;
c1=factorial(a);
c2=factorial(b);
return(c1+c2);
}
long factorial(int n)
{ long rtn=1;
int i;
for(i=1;i<=n;i++)
rtn*=i;
return(rtn);
}
long sum(int a,int b);
long factorial(int n);
文件包含编译预处理命令函数类型说明函数定义函数调用函数调用函数返回值形参实参例子解析你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
18
嵌套调用
C规定,函数定义不可嵌套,但 可以嵌套调用 函数
main( )
调用函数 a
结束
a函数 b函数调用函数 b

6.6 函数的嵌套与递归调用你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
19
#include <stdio.h>
int dif(int x,int y,int z);
int max(int x,int y,int z);
int min(int x,int y,int z);
void main()
{ int a,b,c,d;
scanf("%d%d%d",&a,&b,&c);
d=dif(a,b,c);
printf("Max-Min=%d\n",d);
}
Ch7_202.c
int dif(int x,int y,int z)
{ return max(x,y,z)-min(x,y,z); }
int max(int x,int y,int z)
{ int r;
r=x>y?x:y;
return(r>z?r:z);
}
int min(int x,int y,int z)
{ int r;
r=x<y?x:y;
return(r<z?r:z);
}
main( )
调用函数 dif
输出结束
dif函数 max函数调用函数 max
调用函数 min min函数例 求三个数中最大数和最小数的差值你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
20
定义:函数直接或间接的调用自身叫函数的递归调用
f( )
调 f 调 f2 调 f1
f1( ) f2( )
说明
C编译系统对递归函数的自调用次数没有限制每调用函数一次,在内存堆栈区分配空间,用于存放函数变量、
返回值等信息,所以递归次数过多,可能引起堆栈溢出
int f(int x)
{ int y,z;
……
z=f(y);
…….
return(2*z);
}
int f1(int x)
{ int y,z;
……
z=f2(y);
…….
return(2*z);
}
int f2(int t)
{ int a,c;
……
c=f1(a);
…….
return(3+c);
}
递归调用你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
21

)1()!1(
)1,0(1!
nnn
nn
/*ch7_8.c*/
#include <stdio.h>
int fac(int n)
{ int f;
if(n<0) printf("n<0,data error!");
else if(n==0||n==1) f=1;
else f=fac(n-1)*n;
return(f);
}
main()
{ int n,y;
printf("Input a integer number:");
scanf("%d",&n);
y=fac(n);
printf("%d! =%15d",n,y);
}
例 求 n的阶乘你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
22
6.7 数组作为函数参数
数组元素作函数实参 ——值传递例 两个数组大小比较
4
3
2
1
0
5
a
56
23
12
10
76
88
4
3
2
1
0
5
b
21
23
43
98
66
54
n=0
m=0
k=0
i
n=0
m=0
k=1
i
n=0
m=1
k=1
i
n=1
m=1
k=1
i
n=1
m=1
k=2
i
n=2
m=1
k=2
i
n=3
m=1
k=2
a和 b为有 10个元素的整型数组比较两数组对应元素变量 n,m,k记录 a[i]>b[i],a[i]==b[i],
a[i]<b[i]的个数最后 若 n>k,认为数组 a>b
若 n<k,认为数组 a<b
若 n==k,认为数组 a==b
#include <stdio.h>
main()
{ int a[10],b[10],i,n=0,m=0,k=0;
printf("Enter array a:\n");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
printf("Enter array b:\n");
for(i=0;i<10;i++)
scanf("%d",&b[i]);
for(i=0;i<10;i++)
{ if(large(a[i],b[i])==1) n=n+1;
else if(large(a[i],b[i])==0) m=m+1;
else k=k+1;
}
/* Output */
}
int large(int x,int y)
{ int flag;
if(x>y) flag=1;
else if(x<y) flag=-1;
else flag=0;
return(flag);
}
你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
23
地址传递在主调函数与被调函数分别定义数组,且类型应一致形参数组大小 (多维数组第一维 )可不指定形参数组名是 地址变量数组名作函数参数你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
24
#include <stdio.h>
float average(int stu[10],int n);
void main()
{ int score[10],i;
float av;
printf("Input 10 scores,\n");
for( i=0; i<10; i++ )
scanf("%d",&score[i]);
av=average(score,10);
printf("Average is,%.2f",av);
}
float average(int stu[10],int n)
{ int i;
float av,total=0;
for( i=0; i<n; i++ )
total += stu[i];
av = total/n;
return av;
}
实参用数组名形参用数组定义,?int stu[ ]
.
.
2
1
0
9
score
56
23
12
….
….
88
stu
例 求学生的平均成绩你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
25
1
2
a
调用前
1
2
a
x
调用
2
1
a
x
交换
2
1
a
返回
#include <stdio.h>
void swap2(int x[])
{ int z;
z=x[0]; x[0]=x[1]; x[1]=z;
}
main()
{ int a[2]={1,2};
swap2(a);
printf("a[0]=%d\na[1]=%d\n",a[0],a[1]);
}
地址传递例 数组元素与 数组名作函数参数比较你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
26
void sort(int array[],int n)
{ int i,j,k,t;
for(i=0;i<n-1;i++)
{ k=i;
for(j=i+1;j<n;j++)
if(array[j]<array[k]) k=j;
if(k!=i)
{ t=array[i];
array[i]=array[k];
array[k]=t;
}
}
}
main()
{ int a[10],i;
for(i=0;i<10;i++)
scanf("%d",&a[i]);
sort(a,10);
for(i=0;i<10;i++)
printf("%d ",a[i]);
printf("\n");
}
0
1
2
3
4
5
6
7
8
9
a 49
68
57
32
9
99
27
13
76
88
array kj
j
j k
j k
j
j
j
j
j
9
49
i=0
例 数组排序 ----简单选择排序你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
27
void sort(int array[],int n)
{ int i,j,k,t;
for(i=0;i<n-1;i++)
{ k=i;
for(j=i+1;j<n;j++)
if(array[j]<array[k]) k=j;
if(k!=i)
{ t=array[i];
array[i]=array[k];
array[k]=t;
}
}
}
main()
{ int a[10],i;
for(i=0;i<10;i++)
scanf("%d",&a[i]);
sort(a,10);
for(i=0;i<10;i++)
printf("%d ",a[i]);
printf("\n");
}
k
j
j k
j
kjj
j
j
j
0
1
2
3
4
5
6
7
8
9
a 49
68
57
32
9
99
27
13
76
88
array 9
49
k
k
13
68
i=1
例 数组排序 ----简单选择排序( 1)
你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
28
0
1
2
3
4
5
6
7
8
9
a 9
13
27
32
49
57
68
76
88
99
array
i=8
void sort(int array[],int n)
{ int i,j,k,t;
for(i=0;i<n-1;i++)
{ k=i;
for(j=i+1;j<n;j++)
if(array[j]<array[k]) k=j;
if(k!=i)
{ t=array[i];
array[i]=array[k];
array[k]=t;
}
}
}
main()
{ int a[10],i;
for(i=0;i<10;i++)
scanf("%d",&a[i]);
sort(a,10);
for(i=0;i<10;i++)
printf("%d ",a[i]);
printf("\n");
}
例 数组排序 ----简单选择排序( 2)
你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
29
概述
变量是对程序中数据的存储空间的抽象 内存
…….
main()
{ int a;
a=10;
printf(“%d”,a);
} 102000
2001
程序中使用变量名对内存操作
6.8 变量的存储属性你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
30
变量的属性数据类型:变量所持有的数据的性质( 操作属性 )
存储属性存储器类型:寄存器、静态存储区、动态存储区生存期,变量在某一时刻存在 -------静态变量与动态变量作用域,变量在某区域内有效 -------局部变量与全局变量变量的存储类型
auto -----自动型
register-----寄存器型
static ------静态型
extern -----外部型变量定义格式,[存储类型 ] 数据类型 变量表 ;
概述变量是对程序中数据的存储空间的抽象如,int sum;
auto int a,b,c;
register int i;
static float x,y;
6.8 变量的存储属性你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
31
局部变量 ---内部变量
定义:在 函数内定义,只在本函数内有效
说明:
main中定义的变量只在 main中有效
不同函数中同名变量,占不同内存单元
形参属于局部变量
可定义在复合语句中有效的变量
局部变量可用存储类型,auto register static
(默认为 auto)
float f1(int a)
{ int b,c;
…….
}
char f2(int x,int y)
{ int i,j;
……
}
main()
{ int m,n;
…….
}
a,b,c有效
x,y,i,j有效
m,n有效例 不同函数中同名变量
main()
{ int a,b;
a=3;
b=4;
printf("main:a=%d,b=%d\n",a,b);
sub();
printf("main:a=%d,b=%d\n",a,b);
}
sub()
{ int a,b;
a=6;
b=7;
printf("sub:a=%d,b=%d\n",a,b);
}
例 复合语句中变量
#define N 5
main()
{ int i;
int a[N]={1,2,3,4,5};
for(i=0;i<N/2;i++)
{ int temp;
temp=a[i];
a[i]=a[N-i-1];
a[N-i-1]=temp;
}
for(i=0;i<N;i++)
printf("%d ",a[i]);
}
运行结果,5 4 3 2 1
例 复合语句中变量
#define N 5
main()
{ int i;
t a[N]={1,2,3,4,5};
for(i=0;i<N/2;i++)
{ int temp;
temp=a[i];
a[i]=a[N-i-1];
a[N-i-1]=temp;
}
for(i=0;i<N;i++)
printf("%d ",a[i]);
}
例 不同函数中同名变量
main()
{ int a,b;
a=3;
b=4;
printf("main:a=%d,b=%d\n",a,b);
sub();
printf("main:a=%d,b=%d\n",a,b);
}
sub()
{ int a,b;
a=6;
b=7;
printf("sub:a=%d,b=%d\n",a,b);
}
运行结果:
main:a=3,b=4
sub:a=6,b=7
main:a=3,b=4
局部变量与全局变量你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
32
---外部变量
定义:在 函数外定义,可为 本文件所有函数共用
有效范围:从 定义变量的位置开始 到本源文件结束,及有
extern说明 的其它源文件应尽量少使用全局变量,因为:
全局变量在程序全部执行过程中占用存储单元
降低了函数的通用性、可靠性,可移植性
降低程序清晰性,容易出错定义 说明
次数,只能 1次 可说明多次
位置,所有函数之外 函数内或函数外
分配内存,分配内存,可初始化 不分配内存,不可初始化
>
>
> >
>
>
外部变量说明,extern 数据类型 变量表;
外部变量定义与外部变量说明不同若外部变量与局部变量同名,则外部变量被屏蔽外部变量可用存储类型,缺省 或 static
全局变量你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
33
float max,min;
float average(float array[],int n)
{ int i; float sum=array[0];
max=min=array[0];
for(i=1;i<n;i++)
{ if(array[i]>max) max=array[i];
else if(array[i]<min) min=array[i];
sum+=array[i];
}
return(sum/n);
}
main()
{ int i; float ave,score[10];
/*Input */
ave=average(score,10);
printf("max=%6.2f\nmin=%6.2f\n
average=%6.2f\n",max,min,ave);
}
作用域
max
min
例子解析( 1)
你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
34
int p=1,q=5;
float f1(int a)
{ int b,c;
…….
}
int f3()
{…..
}
char c1,c2;
char f2(int x,int y)
{ int i,j;
……
}
main()
{ int m,n;
…….
}
c1,c2的作用范围
p,q的作用范围
extern char c1,c2;
extern char c1,c2;
c1,c2
的作用范围扩展后 c1,c2
的作用范围扩展后例子解析( 2)
你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
35
int max(int x,int y)
{ int z;
z=x>y?x:y;
return(z);
}
main()
{ extern int a,b;
printf("max=%d",max(a,b));
}
int a=13,b=-8;
运行结果,max=13
extern int a,b;
int max()
{ int z;
z=a>b?a:b;
return(z);
}
main()
{ printf("max=%d",max());
}
int a=13,b=-8;
例 外部变量定义与说明你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
36
/*ch7_17.c*/
int a=3,b=5;
max(int a,int b)
{ int c;
c=a>b?a:b;
return(c);
}
main()
{ int a=8;
printf("max=%d",max(a,b));
}
运行结果,max=8
例 外部变量与局部变量你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
37
存储方式
静态存储:程序运行期间分配固定存储空间
动态存储:程序运行期间根据需要动态分配存储空间
内存用户区程序区静态存储区动态存储区全局变量、局部静态变量形参变量局部动态变量( auto register)
函数调用现场保护和返回地址等生存期静态变量,从程序开始执行到程序结束动态变量,从包含该变量定义的函数开始执行至函数执行结束动态变量与静态变量你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
38
静态动态存储方式程序整个运行期间函数调用开始至结束生存期编译时赋初值,只赋一次每次函数调用时赋初值自动赋初值 0或空字符不确定未赋初值静态存储区动态区存储区 寄存器局部变量 外部变量作用域 定义变量的函数或复合语句内 本文件 其它文件
局部变量默认为 auto型
register型变量个数受限,且不能为 long,double,float型
局部 static变量具有 全局寿命 和 局部可见性
局部 static变量具有 可继承性
extern不是变量定义,可扩展外部变量作用域
register 局部 staticauto 外部 static 外部存储类别变量存储类型你现在所处的位置在,首页?C语言教学?幻灯片版?第六章 函数
39
#include <stdio.h>
int i=1;
main()
{ static int a;
register int b=-10;
int c=0;
printf("-----MAIN------\n");
printf("i:%d a:%d \
b:%d c:%d\n",i,a,b,c);
c=c+8;
other();
printf("-----MAIN------\n");
printf("i:%d a:%d \
b:%d c:%d\n",i,a,b,c);
i=i+10;
other();
}
other()
{ static int a=2;
static int b;
int c=10;
a=a+2; i=i+32; c=c+5;
printf("-----OTHER------\n");
printf("i:%d a:%d \
b:%d c:%d\n",i,a,b,c);
b=a;
}
-------Main------
i:1 a:0 b:-10 c:0
------Other------
i:33 a:4 b:0 c:15
-------Main-----
i:33 a:0 b:-10 c:8
-------Other-------
i:75 a:6 b:4 c:15
全局 i 1
main,a 0
b:-10register
main:c 0
静态存储区动态存储区
other,a 2
other,b 0
other,c 10
8
4
33
15
4
43
6
75
6
例 变量的寿命与可见性