2009-7-31
1
第 8章 函数与预处理命令西亚斯国际学院 自动化
C 语言程序设计
2009-7-31
2复习
1 函数的定义
2 函数的声明
3 函数的调用
– 函数调用的方式:函数语句,函数表达式
– 调用函数所具备的条件。
4 实参与形参的值的单项传递
5 函数的返回值与 return语句
2009-7-31
3复习例题:
试写一个 add()函数,调用该函数时传入起始值( initial)和终值( final),
add()函数会计算起始至终值之间整数的综合( temp),并将计算结果返回
main()函数,再将总和( total)显示到屏幕上。
2009-7-31
4
#include <stdio.h>
void main()
{
int add(int,int);
total=add(5,15);
printf(“\n5+6+7+… +15 is:%d\n”,total);
}
int add(int initial,int final)
{
int temp=0,I;
for(i=initial; i<=final;i++)
{
temp=temp+I;
}
return temp;
}
2009-7-31
58.5 函数的嵌套调用
在调用一个函数的过程中,又调用另一个函数。
函数不能嵌套定义,但是可以嵌套调用。
2009-7-31
6§ 8.6函数的递归调用在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用 。
C语言的特点之一就在于允许函数的递归调用 。
2009-7-31
7
例 8.6.1 有5个人坐在一起,问第5个人多少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大
2岁。问第3个人,又说比第2个人大2岁。问第2个人,说比第1个人大2岁。最后问第1个人,他说是1
0岁。请问第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)
2009-7-31
8
可以用一个函数来描述上述递归过程:
int age( int n) / * */
{ int c; / * c用作存放函数的返回值的变量 */
if(n==1) c=10;
else c=age(n-1)+2;
return(c);

用一个主函数调用 age函数,求得第 5人的年龄。
#include <stdio.h>
void main()

printf( ″%d ″,age(5));

2009-7-31
9§ 8.7数组作为函数参数
1 数组元素作为函数实参(略)。
同普通变量作实参的方式相同。
2 数组名作函数参数
问题:多个返回值的处理?
解决方法一:在被调用函数内整个数组经过计算处理完毕,再将整个数组返回给原调用函数数组。
调用方式:在原调用函数的实参中,只需写上数组名,后面不加 [ ];在被调用函数的形参中,数组名后面加上中括号 [ ]。
2009-7-31
108.7.2 一维数组名作函数参数
数组名 表示数组在内存中的 起始地址 。
例如,数组 a在内存中从 2000地址开始存放,则 a的值为 2000。 2000是地址值,是指针类型的数据(第 8
中将介绍指针类型),不能把它看成是整型或其他类型数据。
实参是数组名,形参也应定义为 数组形式,形参数组的长度可以省略,但 [ ]不能省,否则就不是数组形式了。
【 例 8.7.1】 用冒泡法将 10个整数排序。
2009-7-31
11void sort(int b[ ],int n);
void printarr(int b[ ]);
#include<stdio.h>
void main( )
{ int a[10] =
{11,22,63,98,58,80,45,
32,83,36};
printf("Before
sort:\n");
printarr(a);
sort(a,10);
printf("After sort:\n");
printarr(a);
}
void printarr(int b[10])
{ int i;
for (i=0; i<10; i++)
printf("%5d",b[i]);
printf("\n");}
void sort(int b[ ],int n)
{ int i,j,t;
for (i=1; i<n; i++)
for (j=0; j<n-i; j++ )
if (b[j]>b[j+1])
{ t=b[j];b[j]=b[j+1];b[j+1]=t; }
}
2009-7-31
12
a[0] a[1] a[2] a[3] a[4 ] a[5] a[6] a[7] a[8] a[9]
b[0] b[1] b[2] b[3] b[4] b[5] b[6] b[7] b[8] b[9]
11 22 63 97 58 80 45 32 73 36
(a) 排序前
a[0] a[1] a[2] a[3] a[4 ] a[5] a[6] a[7] a[8] a[9]
b[0] b[1] b[2] b[3] b[4] b[5] b[6] b[7] b[8] b[9]
11 22 32 36 45 58 63 73 80 97
(b) 排序后图 7.3 调用 sort函数
2000b 形参 b 实际是一个可以存放地址的变量a:2000
实参赋给形参首地址:
2000
首地址:
2009-7-31
13
以二维数组为例。二维数组名作实参时,对应的形参也应该定义为一个二维数组形式。对形参数组定义时可以指定每一维的大小,也可以省略第一维的大小说明。
【 例 8.7.2】 编程序,将矩阵转置。设转置前为 a
矩阵,转置后为 b矩阵,如下所示:
a=
1 2 3 4
5 6 7 8
9 10 11 12
1 5 9
2 6 10
3 7 11
4 8 12
b=
思路:将 a[0][0]?b[0][0],a[0][1]?b[1][0],a[0][2]?b[2][0],
a[1][0]?b[0][1],…,a[i][j]?b[j][i],… 。
8.7.3 多维数组名作函数参数
2009-7-31
148.8.2 全局变量及其作用域全局变量 ( 外部变量 ):在 函数外部 定义的变量。
作用域,从定义变量的位置开始到本源文件结束 。如在其作用域内的函数或分程序中定义了同名局部变量,则在局部变量的作用域内,同名全局变量暂时不起作用。
【 例 8.8.1】 全局变量和局部变量的作用域。
2009-7-31
15例 8.8.1
#include "stdio.h"
int a,b,c=30;
void main()
{
void printout();
a=10,b=20;
printf("\n\n In main-block:");
printf("\n a= %d",a);
printf("\n b= %d",b);
printf("\n c= %d",c);
if(1)
{
int a=100;
float b=3.6;
printf("\n\n In IF-block:" );
printf("\n a= %d",a);
printf("\n b= %f",b);
printf("\n c= %d",c);
}
printf("\n\n Exit IF-block but still in main():");
printf("\n a= %d",a);
printf("\n b= %d",b);
printf("\n c= %d",c);
printout();
}
void printout()
{
int d=40;
printf("\n\n In printout
Function:");
printf("\n a= %d",a);
printf("\n b= %d",b);
printf("\n c= %d",c);
printf("\n d= %d",d);
}
2009-7-31
16
建议不在必要时不要使用全局变量,原因如下:
① 全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元。
② 使用全局变量过多,会降低程序的清晰性,人们往往难以清楚地判断出每个瞬时各个外部变量的值。
③它使函数的通用性降低了,因为函数在执行时要依赖于其所在的外部变量。
2009-7-31
17程序的运行结果为?
#include <stdio.h>
int a=3,b=5; /* a,b为外部变量 */ a,b作用范围
void main ( )
{ int a=8; /*a为局部变量 */ 局部变量 a作用范围
printf (″%d″,max (a,b)); 全局变量 b的作用范围
}
max (int a,int b) /*a,b为局部变量 */
{ int c;
c=a> b?a∶ b; 形参 a,b作用范围
return (c);
}
2009-7-31
188.9 变量的存储类别变量的属性数据类型:
决定为变量分配内存单元的长度,
数据的存放形式,
数的范围。
存储类别:
决定了变量的生存期,
给它分配在哪个存储区。
2009-7-31
19变量定义语句的一般形式存储类别 数据类型 变量名 1,…,变量名 n ;
auto(自动的) register(寄存器的)
static(静态的) extern(外部的)
1.自动变量( auto类别)
局部变量可以定义为自动变量。
void void
main()
{int x,y;

}
void void
main()
{auto int x,y;

}
自动变量等价可省
2009-7-31
20
void main()
{ int a,b,c;
printf(“Enter a,b:\n”);
scanf(“%d%d”,&a,&b);
c=sum(a,b);
printf(“Sum=%d\n”,c);
}
sum(int a,int b)
{ int c=0;
c=a+b;
return(c);
}
rintf( ter,b:\,);
sc f( );
c=su (a,b);
printf(“Su =%d\n”,c);
void ain()
Enter a,b:
内存用户区静态存储区
am 不定
bm 不定
cm 不定
1 2 <回车 >
as=1
bs=2
cs=0
bm=2
am=1
s (int a,int b)
Sum=3
程 序程序区动态存储区观察下列程序运行时变量的存储情况单击开始运行
bs=2
cs=3
运行结束
cm =3
2009-7-31
21
⑴ 内存分配调用函数或执行分程序时在 动态存储区 为其分配存储单元,函数或分程序执行结束,所占内存空间即刻释放。
⑵ 变量的初值定义变量时若没赋初值,变量的 初值不确定 ;如果赋初值则每次函数被调用时执行一次赋值操作。
⑶ 生存期在函数或分程序执行期间。
⑷ 作用域自动变量所在的函数内或分程序内。
自动变量
2009-7-31
222.静态变量( static类别)
除形参外,局部变量和全局变量都可以定义为静态变量。
局部静态变量(或称内部静态变量)
全局静态变量(或称外部静态变量)
静态变量
static int a;
main( )
{ float x,y;
… }
f( )
{ static int b=1;
……
}
全局静态变量局部静态变量自动变量不能省
2009-7-31
23
static int b=0;
main( )
{ int a=2,i;
for (i=0; i<2; i++)
printf ("%4d",f(a));
printf("\n");
}
int f(int a)
{ static int c=3;
b++; c++;
return (a+b+c);
}
内存用户区静态存储区程序区动态存储区
【 例 8.9】 静态变量的使用。
b=0
c=3
程 序
am=2
i不定
for (i=0; i<2; i+ )
i=0
printf (" 4d",f(a));
af =2
4
c
1
( 7
1
2
5
9
2
intf( \ );
单击开始运行运行结束
2009-7-31
24
⑴ 内存分配编译时,将其分配在内存的静态存储区中,程序运行结束释放该单元。
⑵ 静态变量的初值若定义时未赋初值,在编译时,系统自动赋初值为
0;若定义时赋初值,则仅在编译时赋初值一次,
程序运行后不再给变量赋初值 。
⑶ 生存期整个程序的执行期间。
⑷ 作用域局部静态变量的作用域是它所在的函数或分程序。
全局静态变量的作用域是从定义处开始到本源文件结束。
静态变量
2009-7-31
25
int c;
static int a;
main( )
{ float x,y;
… }
char s;
f( )
{ static int b=1;
……
}
3.外部变量( extern类别)
在函数外定义的变量若没有用 static说明,则是外部变量。外部变量只能隐式定义为 extern类别,不能显式定义。
全局静态变量自动变量局部静态变量外部变量
2009-7-31
26
⑴ 内存分配编译时,将其分配在静态存储区,程序运行结束释放该单元。
⑵ 变量的初值若定义变量时未赋初值,在编译时,系统自动赋初值为 0。
⑶ 生存期整个程序的执行期间。
⑷ 作用域从定义处开始到本源文件结束。
此外,还可以用 extern进行声明,以使其作用域扩大到该程序的其它文件中。
外部变量问题:
全局静态变量的作用域可以扩展到本程序的其它文件吗?
2009-7-31
27外部变量声明的一般格式
extern 数据类型 变量名 1,…,变量名 n;

extern 变量名 1,…,变量名 n;
注意:
①外部变量声明用关键字 extern,而外部变量的定义不能用 extern,只能隐式定义。
②定义外部变量时,系统要给变量分配存储空间,
而对外部变量声明时,系统不分配存储空间,
只是让编译系统知道该变量是一个已经定义过的外部变量,与函数声明的作用类似。
2009-7-31
284.寄存器变量( register类别)
只有 函数内定义的变量或形参 可以定义为寄存器变量。寄存器变量的值保存在 CPU的寄存器中。
受寄存器长度的限制,寄存器变量只能是 char、
int和指针类型的变量。
【 例 8.10】 寄存器变量的使用。
#include<stdio.h>
void main( )
{ long int sum=0;
register int i;
for (i=1; i<=1000; i++)
sum+=i;
printf("sum=%ld\n ",sum);
}
程序输出结果:
sum=500500
2009-7-31
29归纳变量的分类
1.按照变量的作用域对变量分类
⑴ 局部变量
⑵ 全局变量
2.按照变量的生存期对变量分类
⑴ 静态存储变量包括:局部静态变量和全局静态变量
⑵ 动态存储变量包括:自动变量
2009-7-31
308.8 函数的存储分类 (自学 )
外部函数:
extern int fan(char a,char b)
{ …… }
静态函数:
static int func( )
{ …… }
外部函数 和 静态函数 区别:
外部函数允许本程序其他文件中的函数调用
(与外部变量类似 )。
静态函数 禁止 本程序其他文件中的函数调用
(与外部静态变量类似 )。
extern可以省略
2009-7-31
31
2009-7-31
32
源文件
*.c
运行文件
*.exe编译 编译 编译目标文件
*.obj 连接编译 连接连接编译预处理 编 译编译预处理包括:
宏定义文件包含条件编译
Chapter 9 编译预处理自学不要求