第 7章 函 数第 7章 函 数
7.1 函数的定义
7.2 函数的调用
7.3 数据传递方法
7.4 嵌套调用和递归调用
7.5 变量的作用域
7.6 变量的存储类别
7.7 结构化程序设计方法第 7章 函 数
7.1 函数的定义
1,函数头函数头有经典与现代两种形式,现代形式称之为函数原型 。
经典形式,
函数属性 函数类型 函数名 (函数参数表 )
如,static float f1( a,b,c) /*属性 static,类型 float,函数名 f1,函数参数表 ″a,b,c″/ float a,b,c; /*参数说明 */
现代形式,
函数属性 函数类型 函数名 ( 参数说明 )
如,static double f2( float x,float y,float z)
第 7章 函 数
2,函数体函数体由服务于函数的数据说明与执行语句两部分组成 。 数据说明包括数据定义和数据申明,完成数据描述,执行语句完成操作描述 。 TURBO C中数据说明必须位于函数体或复合语句的开始处,但 C++中可根据需要随时定义 。
一个函数的函数体可以为空,此时的函数称为空函数,
空函数常用于程序调试 。
空函数的形式为,
void f( )
{ }
第 7章 函 数
7.1.2 返回语句通过在函数中使用返回语句,返回一个值给函数,同时终止函数的调用,返回主函数 。
格式,
return( 表达式 ) ;
或 return 表达式 ;
功能,
(1) 计算表达式的值,将表达式的值返回给函数 。
(2) 从被调用的函数返回主调函数。
第 7章 函 数
7.1.3 函数的定义
(1) 需定义函数的属性。
(2) 需定义函数的类型。
(3) 给函数取一个名字。
(4) 设计函数的参数。
(5) 对函数中使用的量进行定义。
(6) 对函数的执行部分进行描述。
第 7章 函 数例 7 – 1 求两个数的最大值函数。
/*求两个数的最大值函数 */
float max( x,y) (1) 函数值类型 float
float x,y; (2) 函数名 max
{float m; (3) 函数参数 x,y,类型为 float
if ( x>y) m=x;
else m=y;
return( m) ; /*返回最大值 */
}
第 7章 函 数说明,
(1) 函数头可以采用现代形式,
float max( float x,float y
(2) 函数体也有多种等价形式,
形式一,if ( x>y) return( x) ;
else return( y) ;
形式二,return( x>y? x,y) ;
第 7章 函 数例 7-2 判断两个数是否是相等函数。
方法一,
/*判断两个数是否是相等函数 */
int eq( x,y) (1) 函数值类型 int,
float x,y; (2) 函数名 eq
{float t; (3) 函数参数 x,y,类型为 float
if ( x==y) t=1;
else t=0;
return( t) ; /*相等返回 1,不等返回 0*/
}
第 7章 函 数方法二,
/*判断两个数是否是相等函数 */
int eq( x,y)
float x,y;
{ if ( x==y) return( 1) ;
else return( 0) ;
}
第 7章 函 数方法三,
/*判断两个数是否是相等函数 */
int eq( x,y)
float x,y;
{return( x==y) ;
}
第 7章 函 数例 7-3 符号函数。
方法一,
/*符号函数 */
char sign( x) (1) 函数值类型 char
float x; (2) 函数名 sign
{char s; (3) 函数参数 x,类型为 float
if ( x>=0) s=′+′;
else s=′-′;
return( s) ;
}
第 7章 函 数方法二,
/*符号函数 */
char sign( x)
float x;
{char s;
if ( x>=0) return( ′+′) ;
else return( ′-′) ;
}
第 7章 函 数例 7-4 求三角形面积函数。
/*求三角形面积函数 */
float sabc( a,b,c) (1) 函数值类型 float
float a,b,c; (2) 函数名 sabc
{float hl; (3) 函数参数 a,b,c,类型为 float
hl=0.5*( a+b+c) ;
return( sqrt( hl*( hl-a) *( hl-b) *( hl-c))) ;
}
第 7章 函 数例 7 – 5
/*素数判断函数 */
int pn( n) (1) 函数值类型 int
int n; (2) 函数名 pn
{int i; (3) 函数参数 n,类型为 int
int flag; /*素数标志 */
flag=1;
for( i=2; i<=n/2; i++
if ( n%i==0) {flag=0; break; }
return( flag) ;
}
第 7章 函 数例 7-6
/* 阶乘函数 */
long int fn( n
int n;
{int i;
long int t;
t=1;
for( i=1; i<=n; i++
t*=i;
return( t) ;
}
第 7章 函 数例 7-7 平方函数 。
/*平方函数 */
float sq( x)
float x;
{return( x*x) ; }
说明,C语言的函数是平等的关系,并列的关系,C
语言的函数体中不能包含函数的定义,不允许嵌套定义 。
第 7章 函 数
7.2 函数的调用
7.2.1 函数调用的一般形式函数调用的一般形式为,
函数名(实参表) ;
第 7章 函 数说明,
(1) 如果调用无参函数,则无实参表,此时小括号不能省略 。
(2) 调用时,实参与形参的个数应相同,类型应一致 。
(3) 实参与形参按顺序对应,一一传递数据 。 调用后,
形参得到实参的值 。
(4) 实参可以是表达式。 如是表达式实参,先计算表达式的值,再将值传递给形参。
第 7章 函 数
(5) 在 C语言中,实参表的求值顺序有的系统按自左至右的常规顺序,有的系统则按自右至左的顺序求实参数值 。
大多数 C( 包括 TURBO C) 采用自右而左的顺序求值 。
例如,int i=3;
printf(,%d,%d”,i,++i) ;
① 实参求值自左至右,输出 3,4;
② 实参求值自右至左,输出 4,4。
为了避免出现意外情况,尽可能将参数表达式的计算移至调用函数前进行 。
(6) 主函数由系统调用 。
第 7章 函 数
7.2.2 函数调用的方式
1,表达式方式函数调用出现在一个表达式中,这种表达式称为函数表达式 。 这时要求函数返回一个确定的值以参加表达式的运算 。
例如,y=max( a,b) +max( c,d),两次函数调用都是表达式的一部分,分别以返回 a与 b,c与 d的最大值参与表达式运算 。
第 7章 函 数
2.
把函数调用作为一个语句 。 常用于只要求函数完成一定的操作,不要求函数返回值 。 这在 scanf( )函数及
printf( )函数的调用中已多次使用 。
在其它高级语言中,函数的调用只能以表达式方式进行 。 C语言中的语句方式调用,实际还是以表达式方式调用为基础 。
第 7章 函 数
3.
函数调用作为另一个函数的实参 。
例如,m=max( max( a,b),max( c,d)),max
( a,b) 与 max( c,d) 两次函数调用作为另一次 max( )
函数调用的实参,用来求出 a,b,c,d的最大值 。
以参数方式调用实际上是表达式调用方式的一种特殊情况。
第 7章 函 数例 7-8 用调用函数的方式来求下面两个三角形的面积。
/*程序 7-8,用调用函数的方式来求三角形的面积 */
float sf( a,b,c) /*求三角形的面积函数 */
float a,b,c;
{float hl;
hl=0.5*( a+b+c) ;
return( sqrt( hl*( hl-a) *( hl-b) *( hl-c))) ;
}
main( ) /*主函数 */
{float x,y,z;
clrscr( );
x=3,y=4,z=5;
第 7章 函 数
if (( x+y>z) &&( y+z>x) &&( z+x>y
printf( ″三边为 %5.2f,%5.2f,%5.2f的三角形面积等于 %5.2f \n″,sf
( x,y,z)) ;
else printf( ″不能构成三角形! \n″) ;
x=y=z=1;
if (( x+y>z) &&( y+z>x) &&( z+x>y
printf( ″三边为 %5.2f,%5.2f,%5.2f的三角形面积等于 %5.2f \n″,sf
( x,y,z)) ;
else printf( ″不能构成三角形! \n″) ;
}
运行结果,
三边为 3.00,4.00,5.00的三角形面积等于 6.00
三边为 1.00,1.00,1.00的三角形面积等于 0.43
第 7章 函 数例 7-9 调用函数求 2~ 1000之间的所有素数。
/*程序 7 - 9,调用函数求 2~ 1000之间的所有素数 */
int pf( n) /*素数判断函数 */
int n;
{int i;
int flag;
flag=1;
for( i=2; i<=n/2; i++
if ( n%i==0) {flag=0; break; }
return( flag) ;
}
第 7章 函 数
main( ) /*主函数 */
{int i;
int count=0; /*统计素数个数,用以控制输出格式 */
clrscr( );
printf( ″2~ 1000之间的素数如下,\n″) ;
for( i=2; i<=1000; i++
if ( pf( i) ==1
{ printf( ″%6d″,i) ;
count++;
if( count%5==0) printf( ″\n″) ; /*每行输出 5个素数 */
}
}
第 7章 函 数
7.2.3 被调函数说明用户自定义函数一般需在调用前在主调函数中进行说明。
函数说明是一种申明,是告诉主调函数这里调用的是一个什么样的函数。
函数说明的一般形式为,
被调函数类型 被调函数名 ( );
注意,不是函数定义,其后有分号。
第 7章 函 数例 7-10 求 2~ n之间的所有素数。
main( )
{int n;
int i;
int count=0;
int pf( ); /*函数说明 */
clrscr( );
printf( ″请输入 n,″) ;
scanf( ″%d″,&n) ;
printf( ″2~ n之间的素数如下,\n″) ;
for( i=2; i<=n; i++
if ( pf( i) ==1) /*调用前申明的函数 */
{ printf( ″%6d″,i) ;
count++;
if( count%5==0) printf( ″\n″) ;
}
}
第 7章 函 数有下面一些情况,在调用函数前可不加说明,
(1) 如果是整型函数或字符型函数,可以不加说明,系统自动按整型函数处理 。
(2) 如果被调用函数的定义出现在主调函数之前,可以不加说明 。 例 7-8,7-9就属于这种情况 。
(3) 如果已在所有函数定义之前,或在文件的开头,或在函数的外部已作说明,可以不加说明 。
除了上述情况,其它情况均必须对被调用的函数在调用前进行说明。
第 7章 函 数另请注意,
(1) 函数一般先定义,后使用 。
(2) 为清晰起见,一般均对被调用的函数在调用前进行说明,以增加程序的可读性 。
(3) 函数不能重复定义,但可以反复说明 。
(4) 对于标准函数,还应在文件开头用文件包含指令# include指明调用有关库函数时所需用到的信息 。
例如,# include ″stdio.h″,stdio.h是一个头文件,它包含了输入输出库函数所用到的一些宏定义信息,
第 7章 函 数
7.3 数据传递方法
C语言程序由若干相对独立的函数组成,在程序运行期间,必然存在数据在函数中流动,流入或流出,这就是函数之间的数据传递,也是函数之间的接口 。 一般语言中,
数据传递有参数传递和全局变量传递两种方法,C语言也提供这两种传递方法 。 参数传递是数据传递的主门 (正门 ),
全局变量传递是数据传递的辅门 (后门 ),数据传递时一般宜用参数传递 。
第 7章 函 数例如,求三个数的最大值,
① 主调函数,……
m=max( a,b,c) ; a b c m( max)
…… ↓↓↓↑
② 被调函数,float max( x,y,z) x y z t
float x,y,z;
{ float t;
t=x;
if( y>t) t=y;
if( z>t) t=z;
return( t) ;
}
第 7章 函 数
7.4 嵌套调用和递归调用
7.4.1 嵌套调用第 7章 函 数例 7-11 定义一个函数求 2~ n之间的完数,调用完数判断函数完成。
/*定义一个函数求 2~ n之间的完数,调用完数判断函数完成 */
void wsh( n
int n;
{int i;
int wf( ); /*函数说明 */
printf( ″2~ %d之间的完数如下,\n″,n) ;
for( i=2; i<=n; i++
if ( wf( i) ==1) printf( ″%6d″,i) ;
}
第 7章 函 数
/*定义一个函数判断 x是否为完数 */
int wf( x
int x;
{int i,s=0;
int w;
for( i=1; i<x; i++
if ( x%i==0) s+=i;
if( s==x) w=1;
else w=0;
return( w) ;
}
函数调用过程,主函数 →wsh( n) →wf( i)
第 7章 函 数例 7-12 定义求组合数函数,
.)!(! ! nmn mC nm
/*求阶乘函数 */
long int jf( n
int n;
{int i;
long int t;
for( t=1,i=1; i<=n; i++
t*=i;
return( t) ;
}
/*求组合数函数 */
long int cmn( m,n
int m,n;
{return( jf( m) /( jf( n) *jf( m-n)) ; }
第 7章 函 数函数调用过程为,
主函数 →cmn( m,n) →jf( m),jf( n),jf( m-n)
第 7章 函 数
7.4.2 递归调用包含有递归调用的函数称为递归函数。
递归算法具有两个基本特征,
(1) 转化。
(2) 终止。
第 7章 函 数例如,计算 n!。
① 转化,n! →( n-1)! →( n-2)! →…→2! → 1! →0
n! =n*( n-1)!
② 终止,n=0,0! =1
相应的递归函数为,
long int jf( n) /*求阶乘的递归函数 */
int n;
{long int j;
if ( n>0) j=n*jf( n-1) ; /*递归调用 */
else j=1; /*递归终止 */
return( j) ; }
第 7章 函 数我们也可先判断是否为递归调用终止条件,如不是,按转化规则转化来写递归函数。
long int jf( n) i
int n;
{long int j;
if ( n==0) j=1; /* 递归终止 */
else j=n*jf( n-1) ; /*递归调用 */
return( j) ;
}
第 7章 函 数如下是计算 4!的过程,
if(4)=4*jf(3) if(4) =24
↓ ↑
if(3)=3*jf(2) if(3)=6
↓ ↑
if(2)=2*jf(1) if(2)=2
↓ ↑
if(1)=1*jf(0) if(1)=1
↓ ↑
if(0)=1
第 7章 函 数例 7-13 用递归方法计算 mn 的函数 。
方法一,
① 转化,mn→mn-1→mn-2→…→m2→m1→m0
mn=m*mn-1
② 终止,n=0,m0 =1
相应的递归函数为,
long int mn( m,n) /* 计算 m 的 n次方递归函数 */
int m,n;
{long int j;
if ( n>0) j=m*mn( m,n-1) ; /*递归调用 */
else j=1; /*递归终止 */
return( j) ; }
第 7章 函 数方法二,
① 转化,n为偶数,mn →mn/2→…→m0,mn=( mn/2) 2
n为奇数,mn→m( n-1) /2→…→m0,mn=m*( m( n-1) /2) 2
② 终止,n=0,m 0 =1
相应的递归函数请读者自己编程实现 。 采用方法二,递归调用的次数比方法一要少许多 。
第 7章 函 数例 7-14 用递归方法计算 Fibonacci数列的第 n项函数。
① 转化,n>2,f( n) =f( n-1) +f( n-2
② 终止,n=1,2,f( 1) =f( 2) =1
相应的递归函数为,
int fib( n) /* 计算 Fibonacci数列的第 n项 */
int n;
{int j;
if ( n>2) j=f( n-1) +f( n-2) ; /*递归调用 */
else j=1; /*递归终止 */
return( j) ; }
第 7章 函 数例 7-15 年龄问题 。 有 5个人坐在一起,问第 5个人多少岁,他说比第 4 个人大 2岁 。 问第 4个人多少岁,他说比第 3个人大 2岁 。 问第 3个人多少岁,又说比第 2个人大 2岁 。 问第 2个人多少岁,说比第 1个人大 2岁 。 最后问第 1个人多少岁,他说是 10岁 。 请问第 5个人多少岁? 。
① 转化,n>1,age( n) =age( n-1) +2
② 终止,n=1,age( 1) =10
第 7章 函 数
age( n) /*求年龄的递归函数 */
int n;
{ int a; /*用作存放函数的返回值 */
if( n==1) a=10;
else a=age( n-1) +2;
return( a) ;
}
main( )/*主函数 */
{
printf( ″第 5个人的年龄 =%d\n″,age( 5)) ;
}
运行结果,第 5个人的年龄 =18
第 7章 函 数
7.5 变量的作用域
7.5.1 局部变量
(1) 在一个函数内部定义的变量是局部变量,只能在函数内部使用 。
(2) 在主函数内部定义的变量也是局部变量,其它函数也不能使用主函数中的变量 。
(3) 形式参数是局部变量 。
(4) 在复合语句中定义的变量是局部于复合语句的变量,只能在复合语句块中使用 。
(5) 局部变量在函数被调用的过程中占有存储单元 。
(6) 不同函数中可以使用同名变量 。
第 7章 函 数例如,有如下程序,
main( )
{int a=1;
int b=2; /*a,b为局部变量 */
{int b=1; /*此 b非前 b,语句块中局部变量 */
printf( ″复合语句中 a=%d,b=%d\n″,a,b) ;
}
printf( ″复合语句外 a=%d,b=%d\n″,a,b) ;
}
运行结果,复合语句中 a=1,b=1
复合语句外 a=1,b=2
第 7章 函 数
7.5.2 全局变量
(1) 在函数外部定义的变量是全局变量,其作用域是变量定义位置至整个程序文件结束 。
(2) 使用全局变量,可增加函数间数据联系的渠道 。
全局变量可以将数据带入在作用域范围内的函数,也可以将数据带回在作用域范围内的其它函数 。
第 7章 函 数
int a,b; /*a,b为全局变量 */
int s( )
{a=a*a; /*函数中 a,b即为前定义的全局变量 */
b=b*b;
return( a+b) ;
}
main( )
{int sum;
a=2;
b=3;
sum=s( );
printf( ″sum=%d,a=%d,b=%d″,sum,a,b) ;
}
运行结果,sum=13,a=4,b=9
第 7章 函 数
(3) 提前引用外部变量,需对外部变量进行说明,或称申明。
形式,extern 类型 变量表 ;
作用,说明这些变量是已在外部定义过的变量。
例如,有如下程序,
main( )
{extern int a,b; /*外部变量说明 */
……
}
int a,b; /*外部变量定义 */
第 7章 函 数
(4) 使用程序中非本程序文件的外部变量,也要对使用的外部变量进行同上的申明,或用文件包含处理 。
(5) 局部变量如与外部变量同名,则在局部变量的作用域内,外部变量存在,但不可见,外部变量的作用被屏蔽 。
(6) 全局变量在程序运行过程中均占用存储单元 。
(7) 在编程时,原则上尽量少用全局变量 ; 能用局部变量,不用全局变量,要避免局部变量全局化 。
第 7章 函 数
7.5.3
从变量的作用域可延伸考虑量的作用域,进一步考虑标识符的作用域,即标识符的使用范围 。 标识符除了标识变量,还用来标识常量,函数,类型等 。
第 7章 函 数
7.6 变量的存储类别
7.6.1 变量的存储类别内存中供用户使用的存储空间分为代码区与数据区两个部分 。 变量存储在数据区,数据区又可分为静态存储区与动态存储区 。
静态存储是指在程序运行期间给变量分配固定存储空间的方式 。 如全局变量存放在静态存储区中,程序运行时分配空间,程序运行完释放 。
第 7章 函 数动态存储是指在程序运行时根据实际需要动态分配存储空间的方式 。 如形式参数存放在动态存储区中,在函数调用时分配空间,调用完成释放 。
对于静态存储方式的变量可在编译时初始化,默认初值为 0或空字符 。 对动态存储方式的变量如不赋初值,则它的值是一个不确定的值 。
在 C语言中,具体的存储类别有自动 ( auto),寄存器
( register),静态 ( static) 及外部 ( extern) 四种 。 静态存储类别与外部存储类别变量存放在静态存储区,自动存储类别变量存放在动态存储区,寄存器存储类别直接送寄存器 。
第 7章 函 数变量存储类别定义方法,
存储类别 类型 变量表 ;
例如,
(1) a,b,c为整型自动存储类别变量,
auto int a,b,c;
(2) x,y,z为双精度型静态存储类别变量,
static double x,y,z;
第 7章 函 数
7.6.2 局部变量的存储方式
(1) 局部变量一般用自动方式存储,用保留字 auto加以定义,此时称为自动变量,是动态存储,在函数的调用过程中存在,由编译系统自动处理 。 例如,
void f( )
{auto int i,j;
auto float x,y; /*局部变量 i,j,x,y以自动方式存储 */
……
}
第 7章 函 数
(2) 如果希望函数调用完后局部变量的值被保留,
不释放其所占存储单元,这时必须将其存储方式定义为静态存储方式,用保留字 static加以定义 。 用静态方式存储的局部变量称为局部静态变量,在函数调用完后其值被保留,由于,局部,的作用域,这个保留的值其它函数并不能使用,只有本函数能够使用 。
第 7章 函 数例 7-16 计算 1到 5的阶乘。
int jf( n
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,jf( i)) ;
}
运行结果为,
1! =1
2! =2
3! =6
4! =24
5! =120
第 7章 函 数
(3) 如果对数据的读写频繁,存取速度要求较快,C语言允许用寄存器方式直接处理变量,用保留字 register加以定义,此时称为寄存器变量 。 例如,
long sum( n)
int n;
{int i;
register long s=0;
for( i=1; i<=n; i++)
s+=i;
return( s) ;
}
第 7章 函 数
(4) 局部变量的缺省存储方式是自动存储方式。
第 7章 函 数
7.6.3 全局变量的存储方式
(1) 全局变量一般用外部存储方式存储,用保留字
extern加以定义 。 此时,变量的作用域是构成整个程序的所有程序文件,也就是定义的外部变量可供其它程序文件使用 。
例如,程序由两个程序文件 file1.c与 file2.c组成。
/*file1.c*/
extern int a; /*定义 extern存储方式变量 a*/
main( )
{int pow( );
int n;
int p;
第 7章 函 数
scanf( ″%d″,&n) ;
p=pow( n) ;
printf( ″p=%d\n″,p) ;
}
/*file2.c*/
extern int a; /*申明本文件中使用的是已定义的外部变量 a*/
int pow( x
int x;
{int i,t=1;
for( i=1; i<=x; i++
t*=i;
return( t) ;
}
第 7章 函 数
2) 如果希望全局变量仅限于本程序文件使用,而其它程序文件中不能引用,这时必须将其存储方式定义为静态存储方式,用保留字 static加以定义 。 此时称为静态外部变量 。
例如,在上例文件 file1.c中,如果作这样的定义,
static int a;
则变量 a的作用域被缩小至本程序文件 file1.c,文件
file2.c中不能引用。
第 7章 函 数
(3) 全局变量的缺省存储方式是外部存储方式 。
前面章节中的程序没有见到变量的存储类别定义,
实际上采用变量的缺省存储方式 。 对局部变量采用
auto方式,对全局变量采用 extern方式 。
第 7章 函 数
1,变量定义的一般形式存储类别 数据类型 变量表 ;
2.
① 规定了变量的取值范围 。
② 规定了变量进行的运行操作 。
③ 规定了变量的作用域 。
④ 规定了变量的存储方式 。
⑤ 规定了变量占用的存储空间。
第 7章 函 数
3,局部变量和全局变量局部变量,
① 自动变量,即动态局部变量 ( 离开函数,值就消失 ).
② 静态局部变量 ( 离开函数,值仍保留 ) 。
③ 寄存器变量 ( 离开函数,值就消失 ) 。
④ 形式参数可以定义为自动变量或寄存器变量。
全局变量,
① 静态外部变量 ( 只限本程序文件使用 ) 。
② 外部变量(即非静态的外部变量,允许其它程序文件引用)。
第 7章 函 数
4,动态存储和静态存储动态存储,
① 自动变量 ( 函数内有效 ) 。
② 寄存器变量 ( 函数内有效 ) 。
③ 形式参数 。
静态存储,
① 静态局部变量 ( 函数内有效 ) 。
② 静态外部变量 ( 本程序文件内有效 ) 。
③ 外部变量(整个程序可引用)。
第 7章 函 数
5,静态存储区和动态存储区从变量值存放的位置可将变量存储区分为静态存储区和动态存储区,
内存中静态存储区,
① 静态局部变量 。
② 静态外部变量 。
③ 外部变量 ( 可被同一程序其它文件引用 ) 。
内存中动态存储区,自动变量和形式参数。
第 7章 函 数例 7-17 仔细阅读程序,注意变量的作用域 #,存储类别,分析程序的运行结果 。
/*程序 7-17,变量的作用域,存储类别 */
void f1( x,y
{auto int i;
static int j; /*调用完,j值保留 */
printf( ″i=%5d,j=%5d\n″,i,j) ;
i=x+y;
j+=x+y;
printf( ″i=%5d,j=%5d\n″,i,j) ;
printf( ″x=%5d,y=%5d\n″,x,y) ;
}
第 7章 函 数
static int k,l,m; /*在本程序文件内使用 */
void f2( a,b,c
int a,b,c;
{ k=a+b+c;
l=a*b*c;
m=k+l;
printf( ″a=%5d,b=%5d,c=%5d\n″,a,b,c) ;
printf( ″k=%5d,l=%5d,m=%5d\n″,k,l,m) ;
}
main( )
{int d,e,f,g,h;
int i,j,x,y,a,b,c;
printf( ″请输入 d,e,f,g,h,″) ;
scanf( ″%d,%d,%d,%d,%d″,&d,&e,&f,&g,&h) ;
printf( ″第一次调用函数 f1( )\n″) ;
f1( d,e) ;
第 7章 函 数
printf( ″i=%5d,j=%5d\n″,i,j) ;
printf( ″x=%5d,y=%5d\n″,x,y) ;
printf( ″d=%5d,e=%5d\n″,d,e) ;
printf( ″第二次调用函数 f1( )\n″) ;
f1( d,e) ;
printf( ″i=%5d,j=%5d\n″,i,j) ;
printf( ″调用函数 f2( )\n″) ;
f2( f,g,h) ;
printf( ″k=%5d,l=%5d,m=%5d\n″,k,l,m) ;
printf( ″a=%5d,b=%5d,c=%5d\n″,a,b,c) ;
printf( ″f=%5d,g=%5d,h=%5d\n″,f,g,h) ;
}
第 7章 函 数运行结果,
请输入 d,e,f,g,h,1,2,3,4,5
第一次调用函数 f1( )
i= 34( 随机值 ),j= 0
i= 3,j= 3
x= 1,y= 2
i= 34( 随机值 ),j= 1985 ( 随机值 )
x= -19( 随机值 ),y= 2340( 随机值 )
d= 1,e= 2
第 7章 函 数第二次调用函数 f1( )
i= 34( 随机值 ),j= 3
i= 3,j= 6
x= 1,y= 2
i= 34( 随机值 ),j= 1985 ( 随机值 )
调用函数 f2( )
a= 3,b= 4,c= 5
k= 12,l = 60,m= 72
k= 12,l = 60,m= 72
a= 13( 随机值 ),b= 124( 随机值 ),c= 2525( 随机值 )
f= 3,g= 4,h= 5
第 7章 函 数
7.7 结构化程序设计方法
7.7.1 程序设计基本手段抽象,枚举与归纳是程序设计的基本手段,也可看作是程序设计的基本原则 。
程序设计语言与程序本身便是一个抽象 。 变量的概念是它当前值的抽象,一般地,数据是对要加工处理的客观对象之抽象,各类控制结构是对计算机操作之抽象,算法是对问题的抽象 。 按此,抽象算法对一些抽象数据实施一系列抽象操作,最终把抽象算法具体化到计算机程序 。
第 7章 函 数
7.7.2 模块化程序设计一个程序由若干模块组成,函数是 C语言中模块的实现工具,较大的模块可用一个程序文件实现 。 模块组装在一起达到整个程序的预期目的 。
一个模块只做一个事情,模块的功能充分独立 。 模块内部的联系要紧密,模块之间的联系要少 。 模块之间通过接口 ( 形参或外部变量 ) 通讯,模块内部的实现细节在模块外部要尽可能不可见 。
第 7章 函 数
7.7.3 结构化程序的书写和阅读例 7-18 编写程序,求解方程 ax2+bx+c=0。
/*程序 7-18,求解方程 a*x*x+b*x+c=0*/
float d; /*判别式,全局变量 */
main( )/*主控程序 */
{float a,b,c; /*方程系数 */
void rf1( ); /*函数申明 */
void rf2( );
void rf3( );
void rf4( );
void rf5( );
void rf6( );
clrscr( );
第 7章 函 数
printf( ″请输入方程系数 a,b,c,″) ;
scanf( ″%f,%f,%f″,&a,&b,&c) ;
d=b*b-4*a*c; /*计算判别式 */
if ( a==0
if ( b==0
if ( c==0) rf1( ); /*调用函数 rf1( )解方程 0x=0*/
else rf2( ); /*调用函数 rf2( )解方程 0x=c*/
else rf3( b,c) ; /*调用函数 rf3( )解方程 bx=c*/
else
if ( d==0) rf4( a,b) ; /*调用函数 rf4( )解方程 a*x*x+b*x+c=0,d=0*/
else if ( d>0) rf5( a,b,c) ; /*调用函数 rf5( )解方程 a*x*x+b*x+c=0,d>0*/
else rf 6( a,b,c) ; /*调用函数 rf6( )解方程 a*x*x+b*x+c=0,d<0*/
}
第 7章 函 数
void rf1( )/*解方程 0x=0*/
{printf( ″方程无数解! \n″) ; }
void rf2( )/*解方程 0x=c*/
{printf( ″方程无解! \n″) ; }
void rf3( b,c) /*解方程 bx=c*/
float b,c;
{float x;
x= -c/b;
printf( ″方程的根 =%6.2f\n″,x) ;
}
void rf4( a,b) /*解方程 a*x*x+b*x+c=0,d=0*/
float a,b;
{float x;
x= -b/( 2*a) ;
printf( ″方程有两个相等实根,根 =%6.2f \n″,x) ;
}
第 7章 函 数
void rf5( a,b,c) /*解方程 a*x*x+b*x+c=0,d>0*/
float a,b,c;
{float x1,x2;
x1=( -b+sqrt( d)) /( 2*a) ;
x2=( -b-sqrt( d)) /( 2*a) ;
printf( ″方程第一个根 =%6.2f,第二个根 =%6.2f \n″,x1,x2) ;
}
void rf6( a,b,c) /*解方程 a*x*x+b*x+c=0,d<0*/
float a,b,c;
{ float r,i;
r= -b/( 2*a) ;
i=sqrt( -d) /( 2*a) ;
printf( ″方程第一个虚根 =%6.2f+%6.2f i\n″,r,i) ;
printf( ″方程第二个虚根 =%6.2f—%6.2f i\n″,r,i) ;
}
第 7章 函 数例 7-19 编写通用面积计算程序 。
(1) 正方形 (2) 长方形 (3) 圆
(4) 三角形 (5) 梯形 (6) 平行四边形
/*程序 7-19 编写通用面积计算程序 */
main( )/*主控程序 */
{char ch; /*选择变量 */
void zs( ); /*函数申明 */
void cs( );
void ys( );
void ss( );
void ds( );
void ps( );
void tc( );
while ( 1)
第 7章 函 数
{ clrscr( ); /*界面显示 */
printf( ″ 通用面积计算程序 \n″) ;
printf( ″Z —正方形面积 C—长方形面积 Y— 圆面积 \n″) ;
printf( ″S—三角形面积 D—梯形面积 P—平行四边形面积 \n″) ;
printf( ″Q—退出程序 \n″) ;
printf( ″请选择操作( Z/C/Y/S/D/P/Q),″) ;
ch=getchar( );
switch ( ch) /*选择处理 */
{ case ′z′,
case ′Z′,zs( ); break;
case ′c′,
case ′C′,cs( ); break;
case ′y′,
case ′Y′,ys( ); break;
case ′s′,
第 7章 函 数
case ′S′,ss( ); break;
case ′d′,
case ′D′,ds( ); break;
case ′p′,
case ′P′,ps( ); break;
case ′q′,
case ′Q′,tc( ); break;
default,printf( ″选择错误! ″) ;
}
}
}
void zs( )/*计算正方形面积 */
{float a;
float s;
printf( ″请输入正方形边长,″) ;
第 7章 函 数
scanf( ″%f″,&a) ;
s=a*a;
printf( ″所求正方形面积 =%7.3f\n″,s) ;
}
void cs( )/*计算长方形面积 */
{float a,b;
float s;
printf( ″请输入长方形长和宽,″) ;
scanf( ″%f,%f″,&a,&b) ;
s=a*b;
printf( ″所求长方形面积 =%7.3f\n″,s) ;
}
# define PI 3.14159
void ys( )/*计算圆面积 */
第 7章 函 数
{float r;
float s;
printf( ″请输入圆半径,″) ;
scanf( ″%f″,&r) ;
s=PI*r*r;
printf( ″所求圆面积 =%7.3f\n″,s) ;
}
void ss( )/*计算三角形面积 */
{float a,b,c;
float l;
int flag;
float s;
printf( ″请输入三角形三边,″) ;
scanf( ″%f,%f,%f″,&a,&b,&c) ;
flag=( a+b>c) &&( b+c>a) &&( c+a>b) ;
第 7章 函 数
if ( flag
{l=0.5*(a+b+c);
s=sqrt( l*( l-a) *( l-b) *( l-c)) ;
printf( ″所求三角形面积 =%7.3f\n″,s) ;
}
else printf( ″不能构成三角形! \n″) ;
}
void ds( )/*计算梯形面积 */
{float a,b,h;
float s;
printf( ″请输入梯形上底,下底,高,″) ;
scanf( ″%f,%f,%f″,&a,&b,&h) ;
s= (a+b)*h*0.5;
printf( ″所求梯形面积 =%7.3f\n″,s) ;
}
第 7章 函 数
void ps( )/*计算平行四边形面积 */
{float a,h;
float s;
printf( ″请输入平行四边形底和高,″) ;
scanf( ″%f,%f″,&a,&h) ;
s= a*h;
printf( ″所求平行四边形面积 =%7.3f\n″,s) ;
}
void tc( )/*退出程序 */
{printf( ″退出面积计算程序! ″) ;
exit( 0) ;
}
第 7章 函 数例 7-20 编写程序,计算 100~ 1000之间的特殊数 。
(1) 素数 (2) 完数 (3) 回文数 (4) 水仙花数
/*程序 7-20,计算 100~ 1000之间的特殊数 */
main( )/*主程序 */
{void ss( ); /*函数申明 */
void ws( );
void hs( );
void shs( );
printf( ″计算 100~ 1000之间的特殊数 \n″) ;
ss( ); /*调用函数 ss( ),ws( ),hs( ),shs( )求出相应特殊数 */
ws( );
hs( );
shs( );
}
第 7章 函 数
void ss( )/*计算 100~ 1000之间的素数 */
{int i,j;
int p;
printf( ″100~ 1000之间素数如下,\n″) ;
for(i=100; i<=1000; i++
{ for(p=1,j=2; j<=i; j++
if( i%j==0) {p= =0; break; }
if( p) printf( ″%8d″,i) ;
}
printf( ″ \n″) ;
}
void ws( ) /*计算 100~ 1000之间的完数 */
{int i,j;
int s;
printf( ″100~ 1000之间完数如下,\n″) ;
for(i=100; i<=1000; i++)
第 7章 函 数
{ for(s=0,j=1; j<i; j++
if( i%j==0) {s+=j; break; }
if( s==i) printf( ″%8d″,i) ;
}
printf( ″ \n″) ;
}
void hs( )/*计算 100~ 1000之间的回文数 */
{int i;
printf( ″100~ 1000之间回文数如下,\n″) ;
for(i=100; i< 1000; i++
if( i%10==i/100) printf( ″%8d″,i) ;
printf( ″ \n″) ;
}
第 7章 函 数
void shs( ) /*计算 100~ 1000之间的水仙花数 */
{int i,i1,i2,i3;
printf( ″100~ 1000之间水仙花数如下,\n″) ;
for(i=100; i<1000; i++
{ i1=( i%10) *( i%10) ;
i2=( i/10%10) *( i/10%10) *( i/10%10) ;
i3=( i/100) *( i/100) *( i/100) ;
if( i==i1+i2+i3) printf( ″%8d″,i) ;
}
printf( ″ \n″) ;
}