第 六 章 函 数
函数的基本使用
函数的嵌套调用
函数的递归调用
变量存储特征
宏函数的概念
k!
n!+m!
f=1;
for(i=1; i<=n; i++)
f=f*i;
scanf("%d%d%d",&m,&n,&k);
fk=1;
for(i=1; i<=k; i++)
fk = fk*i;
fm=1;
for(i=1; i<=m; i++)
fm = fm*i;
fn=1;
for(i=1; i<=n; i++)
fn = fn*i;
printf("%f\n",fm/(fn+fk));
反复使用的代码段
# include <stdio.h>
void main()
{
int k,m,n;
float fk,fm,fn;
scanf("%d%d%d",&m,&n,&k);
fk=1;
for(i=1; i<=k; i++)
fk = fk*i;
fm=1;
for(i=1; i<=m; i++)
fm = fm*i;
fn=1;
for(i=1; i<=n; i++)
fn = fn*i;
printf("%f\n",fm/(fn+fk));
}
# include <stdio.h>
void main()
{
int k,m,n;
float fk,fm,fn;
float fact(int n);
scanf("%d%d%d",&m,&n,&k);
fm = fact(m);
fn = fact(n);
fk = fact(k);
printf("%f\n",fm/(fn+fk));
}
float fact(int n)
{ int i;
float f=1;
for(i=1; i<=n; i++)
f=f*i;
return f;
}
# include <stdio.h>
void main()
{
int k,m,n;
float fk,fm,fn;
float fact(int n);
scanf("%d%d%d",&m,&n,&k);
fm = fact(m);
fn = fact(n);
fk = fact(k);
printf("%f\n",fm/(fn+fk));
}
float fact(int n)
{ int i;
float f=1;
for(i=1; i<=n; i++)
f=f*i;
return f;
}
main
scanf printffact
库函数 自定义函数 库函数
main 主调函数
fact 被调用函数调用定义函数的概念
库函数 scanf() printf() sqrt()
功能独立,反复使用的代码段计算阶乘 fact()
模块化编程学生成绩档案管理软件
┌─────┬─┴──┬────┐
成绩输入 成绩修改 成绩统计 成绩打印
# include <stdio.h>
void main()
{
int in;
printf("1,INPUT 2.EDIT 3,PROCESS 4.PRINT 5.EXIT\n");
while(1){
printf("please input 1-5:");
scanf("%d",&in);
if (in==5) break;
switch(in) {
case 1,input( ); break;
case 2,edit( ); break;
case 3,process( ); break;
case 4,print( ); break;
}
}
}
void input( ) /*,成绩输入 */
{
...............
}
void edit( ) /* 成绩修改 */
{
..............
}
4个函数的 定义
void process( ) /* 成绩统计 */
{
...............
}
void print( ) /* 成绩打印 */
{
...............
}
函数的定义和调用
void main()
{
int m,n;
float fk,fm,fn;
float fact(int n);
fm = fact(6);
……
}
调用 定义
float fact(int n)
{ int i;
float f=1;
for(i=1; i<=n; i++)
f=f*i;
return f;
}
函数的定义和调用返回值类型 函数名 (形式参数表 )
{
……
}
void main()
{
int m,n;
float fk,fm,fn;
float fact(int n);
fm = fact(6);
……
}
float fact(int n)
{ int i;
float f=1;
for(i=1; i<=n; i++)
f=f*i;
return f;
}
调用定义函数名 (实际参数表 )
参数传递返回值类型 函数名 (形式参数表 )
{
……
}
void main()
{
int m,n;
float fk,fm,fn;
float fact(int n);
fm = fact(6);
……
}
float fact(int n)
{ int i;
float f=1;
for(i=1; i<=n; i++)
f=f*i;
return f;
}
1、函数的参数
形式参数类型 1 参数 1,类型 2 参数 2,…… 类型 n 参数 n
定义 函数时需要知道的信息参数个数,0- n
实际参数调用 时由主调函数给出,实参 -> 形参函数的参数函数名 (实际参数表 )
main()
{
……
output( );
……
}
void output( )
{
printf(”**************\n”);
printf(”* very good *\n”);
printf(”**************\n”);
}
main( )
{
int x,y,z;
scanf(“%d%d”,&x,&y);
z=max(x,y);
printf(“%d”,z);
}
int max (int a,int b )
{ int c ;
c=a>b? a,b ;
return( c ) ;
}
问题:
实参可以是表达式吗?
如果实参和形参的类型不一样?
返回值类型 函数名 (形式参数表 )
{
……
}
void main()
{
int m,n;
float fk,fm,fn;
float fact(int n);
fm = fact(6);
……
}
float fact(int n)
{ int i;
float f=1;
for(i=1; i<=n; i++)
f=f*i;
return f;
}
2、返回值类型
函数返回一个值,合法类型
return (exp);
函数的返回值
main()
{
……
output();
……
}
void output( )
{
printf(”**************\n”);
printf(”* very good *\n”);
printf(”**************\n”);
}
2、返回值类型
函数返回一个值,合法类型
return (f);
函数不返回值,void
return; 或省略返回值类型缺省是 int
main( )
{
int x,y,z;
scanf(“%d%d”,&x,&y);
z=max(x,y);
printf(“%d”,z);
}
max(int a,int b )
{
int c ;
c=a>b? a,b ;
return( c ) ;
}
int
问题:
如果返回值的类型与 return (exp)
中的 exp不一致?
实参实参与形参 参数传递
void main()
{
int x,y,z;
scanf(“%d%d”,&x,&y);
z=max( x,y );
printf(“%d”,z)
}
int max(int a,int b )
{
int c;
c=a>b? a,b;
return c;
}
常量变量表达式形参:变量实参与形参 参数传递
int max(int a,int b )
{
int c;
c=a>b? a,b;
return c;
}
void main()
{
int x,y,z;
scanf(“%d%d”,&x,&y);
z=max( x,y );
printf(“%d”,z)
}
x 3
y 5
z
a
b
c 5
3
5
5
1、实参与形参:个数相同、类型一致、按顺序传递
2、实参 -> 形参,值传递单向 形参值的变化不会影响实参的值实参和形参可以同名实参与形参 参数传递
void main()
{
int x,y,z;
scanf(“%d%d”,&x,&y);
z=max( x,y );
printf(“%d”,z)
}
int max(int a,int b )
{
int c;
c=a>b? a,b;
return c;
}
void main( )
{
int x,y;
scanf("%d%d",&x,&y);
swap(x,y);
printf("%d%d",x,y);
}
阅读程序
void swap(int x,int y)
{
int t;
t = x;
x = y;
y = t;
}
输入 3 5
函数的说明
void swap(int a,int b)
{
int t;
t = a;
a = b;
b = t;
}
void main( )
{
int x,y;
scanf("%d%d",&x,&y);
swap(x,y);
printf("%d%d",x,y);
}
void main( )
{
int x,y;
scanf("%d%d",&x,&y);
swap(x,y);
printf("%d%d",x,y);
}
void swap(int a,int b)
{
int t;
t = a;
a = b;
b = t;
}
void swap(int a,int b);
函数在被调用前必须先 定义 或 说明 !
函数调用小结函数调用时,实参 计算值,复制 给 相应位置 的形参;
函数执行完后,通过 return (exp),可返回 结果 。
调用其他函数,
必须先说明!
有多个实参时后面的先计算 形参的改变不影响实参 数量、类型、顺序一致一个结果分析函数调用过程
# include <stdio.h>
void main()
{
int k,m,n;
float fk,fm,fn;
float fact(int n);
scanf("%d%d%d",&m,&n,&k);
fm = fact(m);
fn = fact(n);
fk = fact(k);
printf("%f\n",fm/(fn+fk));
}
float fact(int n)
{ int i;
float f=1;
for(i=1; i<=n; i++)
f=f*i;
return f;
}
例 T6-1 1!+2!+……+n!
算法:
k =1 to n
s=s+f
f=k!
k++
s=0;
for(k=1;k<=n;k++){
f=fact(k);
s=s+f;
}
float fact(int n)
{
int i;
float f=1;
for(i=1; i<=n; i++)
f=f*i;
return(f);
}
例 T6-2 x+x2+……+x n
算法:
k =1 to n
s=s+f
f= xk
k++
s=0;
for(k=1;k<=n;k++){
f=mypow(x,k);
s=s+f;
}
float mypow(float x,int n)
{
int i;
float f=1;
for(i=1; i<=n; i++)
f = f*x;
return(f);
}
例 T6-3 编写函数 比较 2个变量是否相等
equal(x,y)
当 x==y,返回 1
否则,返回 0
int equal(int x,int y)
{
if(x==y) return 1;
else return 0;
}
void main( )
{
int x,y;
scanf("%d%d",&x,&y);
if(equal(x,y))
printf("x==y");
else
printf("x! =y");
}
int equal(int x,int y)
{
return(x==y);
}
例 T6-4 输出 100~200间所有素数算法:
m =100 to 200
if m是素数
print m int prime(int m)
{ int i,n=sqrt(m);
for(i=2; i<=n; i++)
if(m%i==0) break;
if(i>n) return 1;
else return 0;
}
for(m=100; m<=200; m++){
if(prime(m))
printf("%d",m)
}
prime(m)
if m是素数,返回 1
否则,返回 0
函数的顺序调用和嵌套调用
顺序调用
void main( )
{ ……
f1( );
……
f2( );
……
}
f1()
{ ……
}
f2()
{ ……
}
main
f1 f2
main
f1
f2
函数的顺序调用和嵌套调用
嵌套调用
void main( )
{ ……
f1( );
……
}
f1()
{ ……
f2( );
……
}
f2()
{ ……
}
main
f1 f2
main
f1
f2
例 求三角形面积 area=s(s-a)(s-b)(s-c)
s=(a+b+c)/2 main
area
s
main
area s
# include <stdio.h>
# include <math.h>
void main()
{ float a,b,c;
float area(float a,float b,float c);
float s(float a,float b,float c);
scanf("%f%f%f",&a,&b,&c);
printf("%f\n",area(a,b,c));
}
float area(float a,float b,float c)
{ float ss;
ss=s(a,b,c);
return sqrt(ss*(ss-a)*(ss-b)*(ss-c));
}
float s(float a,float b,float c)
{
return (a+b+c)/2;
}
递归式递归出口函数的递归调用 (递归函数 )
求 n!
递归定义 n! = n * (n-1)! (n > 1)
n! = 1 (n = 0,1)
void main()
{ float fact(int n);
printf("%f\n",fact(5));
}
float fact(int n)
{ float res;
if(n==0 || n==1)
res=1;
else
res = n*fact(n-1);
return res;
} fact(n)=n*fact(n-1);
递归函数求 n! 的实现过程
fact(3)
3*fact(2)
2*fact(1) 1
2
6 float fact(int n)
{ float res;
if(n==0 || n==1)
res=1;
else
res = n*fact(n-1);
return res;
}
函数的递归调用 (递归函数 )
用递归实现的问题,满足两个条件:
问题可以逐步简化成自身较简单的形式 (递归式 )
n! = n * (n-1)!
n n-1
Σi = n +Σ i
i=1 i=1
递归最终能结束 (递归出口 )
两个条件缺一不可解决递归问题的两个着眼点变量作用范围 (作用域 )
在函数内定义的变量(包括形参)。
局部变量 作用范围:本函数内部 。
定义在复合语句内的变量。
作用范围:复合语句内部 。
全局变量,在函数以外定义的变量,不从 属 于任一函数。
作用范围:从定义处到源文件结束 (包括各函数)
变量作用范围示例
区分局部变量和全局变量
int x=1;
void main( )
{ int a=2;
……..
{
int b=3;
…..
}
f( );
………..
}
int t=4 ;
void f( )
{ int x=5,b=6;…….
}
int a=7;
x=? a=? b=?
b=?
x=? b=? t=? a=?
x=1 a=2 b=3
没定义
5 b=6 t=4 a没定义若局部变量与全局变量同名,
局部变量优先变量作用范围示例
int x=1;
int f(int x)
{
return(x++);
}
main( )
{ int y;
y=f(2) ;
x=f(x) ;
printf(“%d%d”,y,x);
}
x=1
变量作用范围
如果局部变量与全局变量同名,
局部变量优先。
不要滥用全局变量。 副作用
int x=1;
void f1()
{
x++;
}
void f2()
{
x=5;
}
void main( )
{ x=10;
f1();
printf("%d ",x);
f2();
printf("%d ",x);
}
11 5
变量存储形式和生存期
1,动态存储自动变量 (auto),普通的局部变量
int x,y; auto int x,y;
char c1; auto char c1;?
函数调用时,才定义变量,分配存储单元;?
函数调用结束,收回存储单元。
即使对同一函数的几次调用,分配的存储单元也不同 。
fact(3)
3*fact(2)
2*fact(1) 1
2
6 float fact(int n){ float res;
if(n==0 || n==1)
res=1;
else
res = n*fact(n-1);
return res;
}
n=3
n=2
n=1
变量存储形式
2,静态存储在静态存储区分配单元执行程序时定义变量,分配单元,运行结束时收回 。
全局变量?
静态局部变量?
静态全局变量
int k;
main()
{ int i;
k=2;
for(i=4; i>0; i--)
fun();
}
fun()
{ int j=2;
printf("j=%d,k=%d\n",j,k);
k=k*k;
j=j*j;
}
示例
j=2,k=2
j=2,k=4
j=2,k=16
j=2,k=256
作用域生存期
int gobal=1;
void fun();
void main()
{ int i;
for(i=0; i<3; i++)
fun();
}
void fun()
{ int local=1;
static int static_local=1;
printf("gobal=%d,local=%d,static_local=%d\n",gobal,local,static_local);
gobal++;
local++;
static_local++;
}
静态局部变量
gobal=1,local=1,static_local=1
gobal=2,local=1,static_local=2
gobal=3,local=1,static_local=3
作用域 生存期
int gobal=1;
void fun();
void main()
{ int i;
for(i=0; i<3; i++)
fun();
}
void fun()
{ int local=1;
static int static_local=1;
printf("gobal=%d,local=%d,static_local=%d\n",gobal,local,static_local);
gobal++;
local++;
static_local++;
}
变量的初始化作用域 生存期
int local;
local=1; static int static_local;
static_local=1;
等价吗?
静态变量初值为 0
变量存储形式
3、外部变量
extern int x;
4、寄存器变量
register int k;
某些系统对寄存器变量的使用会比普通变量运行速度快,但TC中寄存器变量与 auto变量等价。
程序模块结构文件模块的连接
#include "F1.c"
void main()
{
int n;
long t;
scanf("%d",&n);
t = fact(n);
printf("%ld\n",t);
}
文件名 F1.c
long fact(int k)
{
int i;
long res=1;
for (i=1; i<=k ; i++)
res = res * i;
return res;
}
文件名 F2.c
long fact(int k)
{
int i;
long res=1;
for (i=1; i<=k ; i++)
res = res * i;
return res;
}
void main()
{
int n;
long t;
scanf("%d",&n);
t = fact(n);
printf("%ld\n",t);
}
文件名 F1.c
程序模块结构一,文件包含可以实现一个文件把另一个文件的全部内容包含进来。
格式,# include "文件名 "
说明:
1,#include 不是C语句,无需分号。
2、如果要连接多个文件,可用多个 include包含,顺序按调用关系,被调的应在调用的前面。允许多层调用。
3,".h "文件与 ".c "性质相同,都是C程序文件,".h "文件突出了头文件 (head)的性质。
4,include有两种写法:
#include,file1.c"
#include <stdio.h>
<……> 只在 tc\include 文件夹下找
—— 适用于系统头文件
"……" 除此之外,还到程序所在文件夹下查找
—— 适用于自定义头文件二、使用工程文件
extern long fact(int k);
void main()
{
int n;
long t;
scanf("%d",&n);
t = fact(n);
printf("%ld\n",t);
}
文件名 file1.c
long fact(int k)
{
int i;
long res=1;
for (i=1; i<=k ; i++)
res = res * i;
return res;
}
文件名 F2.c
外部变量两个文件分别独立 编译,进行 连接 时会自动连接
file1.obj和 file2.obj,形成一个完整的可执行文件。
int x;
extern int f1();
void main()
{ f1( );
………
}
文件名 file1.c
extern x;
/*使用 file1.c中的全局变量 x */
f1( )
{
………
}
文件名 file2.c扩大全局变量的作用域调用另一模块中的函数静态全局变量静态全局变量(或函数)将只限制在一个文件中使用,可以避免不同人编写程序时的相互干扰。
static int x;
extern int f1();
void main()
{ f1( );
………
}
文件名 file1.c
extern x;
/*使用 file1.c中的全局变量 x */
static int f1( )
{
………
}
文件名 file2.c无法引用无法调用限制全局变量的作用域变量存储类别小结存储类别函数内 函数外初值作用域 生存期 作用域 生存期局部变量
auto / register √ √ ╳ ╳ 随机静态局部变量 √ √ ╳ √ 0
全局变量静态全局变量 √ √ √本文件 √ 0
全局变量 √ √ √ √ 0
宏定义
# define 宏名标识符 宏定义字符串编译 时,把程序中所有与宏名相同的字符串,
用宏定义字符串 替代 。
# define PI 3.14
# define arr_size 4
带参数的宏定义例:用宏实现两个变量值的交换
# define f(a,b,t) t=a; a=b; b=t;
void main( )
{ int x,y,t ;
scanf(“%d%d”,&x,&y);
f(x,y,t)
printf(“%d %d\n”,x,y) ;
}
t=x; x=y; y=t;
编译时被替换注意,
(1) 带参数的宏定义不是函数,宏与函数是两种不同的概念。
(2) 宏可以实现简单的函数功能