内容正文:
7.1 函数概述
7.2 函数的声明
7.3 函数定义和函数调用
7.4 程序举例
7.5 函数的嵌套调用和递归调用
7.6 变量的作用域
7.7 变量的存储类别
7.1 函数概述
模块化程序设计
基本思想:将一个大的程序按功能分割成一些小模块。
特点:
各模块相对独立、功能单一、结构清晰、接口简单
控制了程序设计的复杂性
缩短开发周期
避免程序开发的重复劳动
易于维护和功能扩充
开发方法: 自上向下,逐步分解,分而治之
>
<
【例7.1】 计算5!+6!+7!并输出结果。
#include <stdio.h>
main( )
{
int i,t,num1=5,num2=6,num3=7,sum=0;
for (i=1,t=1;i<=num1;i++)
t=t*i;
sum=sum+t;
for (i=1,t=1;i<=num2;i++)
t=t*i;
sum=sum+t;
for (i=1,t=1;i<=num3;i++)
t=t*i;
sum=sum+t;
printf("5!+6!+7!=%d
",sum);
}
出现重复
>
<
#include <stdio.h>
int fac( int num);
main( )
{
int t1,t2,t3,sum=0;
t1=fac(5);
t2=fac(6);
t3=fac(7);
sum=t1+t2+t3;
printf("5!+6!+7!=%d
",sum);
}
int fac( int num) /* 定义fac函数,num是形参 */
{
int i,t;
for(i=1,t=1;i<=num;i++)
t=t*i;
return t; /* 函数的返回值 */
}
>
<
7.2 函数的声明
函数声明的一般形式如下:
类型标识符 函数名(类型 形参名1, 类型 形参名2,…);
或
类型标识符 函数名(类型, 类型,…);
#include <stdio.h>
int fac( int num); /* 对函数fac的声明语句 */
main( )
{
...
}
>
<
7.3 函数定义和函数调用
函数类型 函数名(形参类型说明表)
{
说明部分
语句部分
}
函数定义:
>
<
函数的调用
调用形式
函数名(实参表);
说明:
实参与形参个数相等,类型一致,按顺序一一对应
实参表求值顺序,因系统而定
>
<
#include <stdio.h>
int max(int a,int b); /* 函数原型的声明 */
int main( )
{
int x,y,z;
printf("input two numbers:
");
scanf("%d%d",&x,&y);
z=max(x,y); /* 函数的调用语句 */
printf("maxmum=%d",z);
return 0;
}
/*以下是函数的定义部分*/
int max(int a,int b)
{
if(a>b) return a;
else return b;
}
实参
形参
>
<
7.5 函数的嵌套调用和递归调用
7.5.1嵌套调用
C规定:函数定义不可嵌套,但可以嵌套调用函数
例7.7输入两个整数,输出较大值 的函数调用过程如下图所示。
>
<
7.5.2 函数的递归调用
递归是一种特殊的解决问题的方法。其基本思想是:将要解决的问题分解成比原问题规模小的类似子问题,而解决这个类似子问题时,又可以用到原有问题的解决方法,按照这一原则,逐步递推转化下去,最终将原问题转化成较小且有已知解的子问题。
(1)递推阶段:将原问题不断地转化成子问题,逐渐从未知向已知推进,最终到达已知解的问题,递推阶段结束。
(2)回归阶段:从已知解的问题出发,按照递推的逆过程,逐一求值回归,最后到达递归的开始处,结束回归阶段,获得问题的解。
例如:求5!
递推阶段5!=5×4!→4!=4×3!→3!=3×2!→2!=2×1!→1!停止,其中1!=1
回归阶段5!=5×4!=120←4!=4×3!=24←3!=3×2!=6←2!=2×1!=2←1!=1
>
<
>
<
例 : 有5个人坐在一起,问第5个人多少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。问第3个人,又说比第2个人大2岁。问第2个人,说比第1个人大2岁。最后问第1个人,他说是10岁。请问第5个人多大。
age(5)= age (4)+2
age(4)= age (3)+2
age(3)= age (2)+2
age(2)= age (1)+2
age(1)= 10
用数学公式表述如下:
age(n)= 10 (n=1)
age(n-1)+2 (n>1)
>
<
age(5)
c=age(4)+2;
return c;
age(int n)
{
int c;
if (n==1) c=10;
else c=age(n-1)+2;
return c;
}
递归过程
跟踪分析:
age(4)
c=age(3)+2;
return c;
age(3)
c=age(2)+2;
return c;
age(2)
c=age(1)+2;
return c;
age(1)
c=10
return c;
c=10
c=12
c=14
c=16
c=18
7.6 变量的作用域
7.6.1 局部变量
1、定义:在一个函数(或复合语句) 内部定义的变量。
2、作用域:本函数(或复合语句)
它只在本函数范围(或复合语句)内有效,也就是说只有在本函数(或复合语句)内才能使用它们,在此函数以外是不能使用这些变量的。
>
<
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有效
3、说明
(1)形式参数是局部变量。
如f1中形参a,出了f1函数就无效。
(2)main中定义的变量只在main中有效,也是局部变量。
不能因为在main函数中定义就在整个文件或程序中有效。 main函数也不能使用其它函数中定义的变量。
>
<
例 不同函数中同名变量
main()
{ int a,b;
a=3;
b=4;
printf("main:a=%d,b=%d
",a,b);
sub();
printf("main:a=%d,b=%d
",a,b);
}
sub()
{ int a,b;
a=6;
b=7;
printf("sub:a=%d,b=%d
",a,b);
}
运行结果:
main:a=3,b=4
sub:a=6,b=7
main:a=3,b=4
3、说明
(3)不同函数中的同名变量,占有不同内存单元,因此不会相互影响
>
<
3、说明
(4)复合语句中的变量
运行结果:5 4 3 2 1
例 复合语句中变量
#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]);
}
变量temp只在本复合语句中有效,离开该复合语句就无效,释放内存。
>
<
1、定义:在所有函数外部定义的变量。
全局变量可以为本文件中其他函数所共用。
2、作用域:从定义变量的位置开始到本源文件结束,及有
extern说明的其它源文件。
7.6.2 全局变量
>
<
3、说明:
(1)有效范围:从定义或有extern声明的位置开始,直至它所在源程序文件的结束。
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的作用范围
>
<
3、说明:
(2) 若外部变量与局部变量同名,则外部变量被屏蔽
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
>
<
内存
…….
main()
{ int a;
a=10;
printf(“%d”,a);
}
编译或函数调用时为其分配内存单元
10
2000
2001
程序中使用变量名对内存操作
在C语言中每一个变量和函数有两个属性:
数据类型和数据的存储类别。
7.7 变量的存储类别
>
<
静态变量:存储在静态存储区的变量。
在程序运行期间分配固定的存储空间不释放
生存期:从程序开始执行到程序结束
动态变量:存储在动态区的变量。
在程序运行期间根据需要临时分配存储空间,离开即释放
生存期:从包含该变量定义的函数开始执行至函数执行结束
存储类别:指 变量、函数等存储的方式和位置
存储器类型:寄存器、静态存储区、动态存储区
程序区
静态存储区
动态存储区
全局变量、局部静态变量
形参变量
局部动态变量(auto register)
函数调用现场保护和返回地址等
>
<
变量的存储类型
auto -----自动型
register-----寄存器型
static ------静态型
extern -----外部型
变量定义格式: [存储类型] 数据类型 变量表;
如: int sum;
auto int a,b,c;
register int i;
static float x,y;
>
<
auto(自动)变量
没有声明为static的局部变量都属于此类。
如:函数中的形参和在函数中定义的变量(包括在复合语句中定义的变量)。
存储特性:存储在动态存储区。
调用时自动动态分配存储空间。调用结束后自动释放存储空间。
例如:
int f(int a) /*定义f函数,a为形参 */
{
auto int b,c=3;/*定义b、c为自动变量 */
…
}
执行完f后,自动释放a、b、c所占的内存。
auto int b, c=3和int b, c=3等价。
>
<
register(寄存器)变量
只有auto变量与形式参数可以作为register变量
register变量和auto变量不同之处在于register变量存放在CPU的寄存器中,因此比auto变量存取速度快。通常将频繁使用的变量放在寄存器中,以提高程序执行速度
不能对寄存器变量使用取地址运算符&
计算机中寄存器的数量是有限的,而且寄存器的数据长度也是有限的。因此register变量不能定义太多,也不能是数据类型太大的变量(long、float、double型)
目前register变量定义通常是不必要的,优化的编译系统能够识别使用频繁的变量,并将其放到寄存器中
>
<
static(静态)变量
static变量存放在内存的静态存储区,在整个程序运行期间占用固定的内存单元。
可以修饰局部变量和全局变量。
系统在编译时为static变量分配空间并赋初值,对未赋值的局部static数值型变量,系统自动给它赋值为0;对未赋值的局部static字符型变量,自动赋值为空字符。因为在编译时赋初值,所以只能赋一次初值且只能在定义时进行。
由于变量占用的存储单元不消失,再次调用static局部变量时,static局部变量的值为上次调用结束时的值。
注意:static局部变量的生存期是整个程序运行期间,但作用域仍然是定义该变量的函数体(或复合语句)内部。
即:静态局部变量在函数调用结束后仍然存在,但其他函数不能引用它。
static修饰全局变量,将使全局变量作用域局限于本文件内。
>
<
main()
{ void increment(void);
increment();
increment();
increment();
}
void increment(void)
{ int x=0;
x++;
printf(“%d
”,x);
}
练习 局部静态变量值具有可继承性
运行结果:1
1
1
main()
{ void increment(void);
increment();
increment();
increment();
}
void increment(void)
{ static int x=0;
x++;
printf(“%d
”,x);
}
运行结果:1
2
3
>
<
#include <stdio.h>
void main()
{
int f(int);
int a=2,i;
for (i=0;i<3;i++)
printf(“%d”,f(a));
}
int f(int a)
{ auto int b=0;
int c=3;
b=b+1;
c=c+1;
return(a+b+c);
}
考察静态局部变量的值。
#include <stdio.h>
void main()
{
int f(int);
int a=2,i;
for (i=0;i<3;i++)
printf(“%d”,f(a));
}
int f(int a)
{ auto int b=0;
static int c=3;
b=b+1;
c=c+1;
return(a+b+c);
}
结果:7,8,9
b、c是自动变量,函数调用结束后, b、c的存储空间释放。
再一次调用, b、c重新赋值。
c是静态局部变量,在整个程序运行期间,c的空间都不释放,函数调用结束后后,c的值仍保留
再一次调用, c的值为保留的值。
结果:7,7,7
extern声明(外部)变量
全局变量都是存放在静态存储区中的。因此它们的生存期是固定的,存在于程序的整个运行过程。
全局变量是在函数的外部定义的,它的作用域是从变量的定义处开始,到本程序文件的末尾。
采用extern可以扩充全局变量的作用域。
外部变量定义与外部变量声明不同
>
<
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
的作用范围
扩展后
extern对全局变量作用域的扩展
在多文件的程序中,引用其它文件中的外部变量需extern声明
例
int global;
extern float x;
main()
{ int local;
.
.
.
}
extern int global;
static int number;
func2()
{ .
.
.
}
float x;
static int number;
func3()
{ extern int global;
.
.
.
}
file1.c
file2.c
file3.c
用extern将外部变量的作用域扩展到其他文件。
>
<
返回值
函数体
形参名
形参类型
函数名
返回值类型
int fac ( int num)
{
int i,t;
for(i=1,t=1;i<=num;i++)
t=t*i;
return t;
}
实参
b
a
20
10
20
10
y
x
形参
larger( )
{
…
返回
}
process( )
{
…
larger( );
…
返回
}
main( )
{
…
process( );
…
}
24
6
2
1
1
2
3
4
int factorial(int n)
{
if (n==1)
return 1;
else
return (n*factorial(n-1));
}
int factorial(int n)
{
if (n==1)
return1;
else
return (n*factorial(n-1));
}
int factorial(int n)
{
if (n==1)
return1;
else
return (n*factorial(n-1));
}
int factorial(int n)
{
if (n==1)
return1;
else
return (n*factorial(n-1));
}
{
int n=4;
long f;
f=factorial(4);
printf(“%d
”,f);
}/*main function*/
$$