第十章带参数的函数
2
回顾 2-1
函数是程序中的一个相对独立的单元或模块
使用函数带来的好处,程序更清晰、易维护、分模块方便设计与开发、提高代码的重用性
C语言提供了极为丰富的内置函数,要使用这些内置函数,需要在程序前包含相应的头文件
自定义函数是用户在程序中根据需要而编写的函数
3
回顾 2-2
函数的结构包括:返回值类型、函数名、参数列表、函数体
函数原型说明以便向编译器指出该函数使用什么样的格式和语法
函数调用时程序控制流将转向被调函数,被调函数执行结束时,控制流返回主调函数
return 语句用于向调用函数返回值
4
目标
理解变量的作用域
理解变量的存储类型
理解两种参数传递的方式:传值、引用
熟悉带参函数的调用
熟练使用数组作为函数参数
5
变量的作用域 4-1
作用域是某些事物起作用或有效的区域。
限于陆地限于海洋限于空中
6
程序中变量也有不同的使用范围,称为变量的作用域。变量的作用域决定变量的可访问性变量的作用域 4-2
void displayDiscount()
{
float discount_amt;
.,,
.,,
.,,
}
局部变量:不能在函数外使用
float discount_amt;
void main()
{
.,,
.,,
}
void displayDiscount()
{
.,,
.,,
}
全局变量:可以在整个程序中使用
7
变量的作用域 4-3
#include <stdio.h>
void addNumbers()
{
int num1,num2,sum;
printf("\n 请输入两个数,");
scanf("%d %d",&num1,&num2);
sum=num1+num2;
printf(" 子函数中 sum 的值是 %d \n",sum);
}
void main()
{
int sum=0;
addNumbers();
printf("\n 主函数中 sum 的值是 %d \n ",sum);
}
内存
sum
num20
45
num1
请输入两个数,56 45
子函数中 sum的值是 101
主函数中 sum的值是 0
56
sum
101
8
变量的作用域 4-4
#include <stdio.h>
int sum=0;
void addNumbers()
{
int num1,num2;
printf("\n 请输入两个数,");
scanf("%d %d",&num1,&num2);
sum=num1+num2;
printf(" 子函数中 sum 的值是 %d \n",sum);
}
void main()
{
addNumbers();
printf("\n 主函数中 sum 的值是 %d \n ",sum);
}
内存
sum
num20
45
num1
请输入两个数,56 45
子函数中 sum的值是 101
主函数中 sum的值是 101
56
101
9
存储类型 2-1
变量的存储方式可分为“静态存储”和“动态存储”两种
静态存储变量是一直存在的,而动态存储变量则时而存在时而消失
这种由于变量存储方式不同而产生的特性称为变量的生存期
生存期表示了变量存在的时间
10
存储类型 2-2
存储类型 说明
auto 自动变量 局部变量在缺省存储类型的情况下归为自动变量。
register 寄存器变量存放在 CPU的寄存器中。对于循环次数较多的循环控制变量及循环体内反复使用的变量均可定义为寄存器变量。
static 静态变量 在程序执行时存在,并且只要整个程序在运行,就可以继续访问该变量。
extern 外部变量 作用域是整个程序,包含该程序的各个文件。
生存期非常长,它在该程序运行结束后,才释放内存。
11
静态局部变量
静态局部变量生存期为整个源程序
静态局部变量作用域与自动变量相同,即只能在定义该变量的函数内使用该变量
对基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予 0值
函数被调用时,其中的静态局部变量的值将保留前次被调用的结果
12
静态局部变量示例
void format()
{
static int m = 0;
m++;
if (m % 10 == 0)
putchar('\n');
else
putchar(' ');
}
void main()
{
int i;
for(i=0;i<50;i++)
{
printf("%d",i);
format();
}
}
内存
i
0
m
0
11
循环执行 50次
49 49
0 11 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
2
13
静态全局变量
静态全局变量与普通全局变量在存储方式上完全相同
区别在于:非静态全局变量的作用域是整个源程序;而静态全局变量的作用域只是定义它的文件
14
函数形参和实参
void main ( )
{
.,,
.,,
display ( 10,20.5 );
}
display ( int num,float fraction )
{
.,,
.,,
}
实际参数函数调用形式参数
15
void main()
{
int a = 0; //初始化 a值为 0
func(a); //调用函数 func
printf("%d",a); //输出 a的结果
}
//定义函数 func
void func(int a)
{
a = 10; //让参数 a等于 10
}
传值调用
0
传值调用将会输出什么
16
#include <stdio.h>
void increment(int,int);
void main()
{
int num1,num2;
printf("\n 请输入两个数,");
scanf(" %d %d",&num1,&num2);
printf("\n 递增前的值是 %d 和 %d\n",num1,num2);
increment(num1,num2);
printf("\n 递增后的值是 %d 和 %d\n",num1,num2);
}
void increment(int val1,int val2)
{
val1++;
val2++;
printf("\n 子函数中值 %d 和 %d\n",val1,val2);
}
传值调用示例请输入两个数,34 56递增前的值是 34 和 56_
递增后的值是 34 和 56
num1 num2
var1
34 56
var2
子函数中的值是 35 和 57
35
34 56
57
num1 num2
34 56
34 56
FF23 FF05
调用后修改为 35 val2
FFEA FF45
将变量 num1的值赋给形参 val1
将变量 num2的值赋给形参 val2
val1 调用后修改为 57
调用函数被调用函数
17
void main()
{
int a = 0; //初始化 a值为 0
func(&a); //调用函数 F
printf("%d",a); //输出 a的结果
}
//定义函数 F
void func(int *a)
{
*a = 10; //让参数 a等于 10
}
引用调用
FFE0
引用调用
a=FFE0
将会输出什么
18
#include <stdio.h>
void increment(int*,int*);
void main()
{
int num1,num2;
printf("\n 请输入两个数,");
scanf(" %d %d",&num1,&num2);
printf("\n 递增前的值是 %d 和 %d\n",num1,num2);
increment(&num1,&num2);
printf("\n 递增后的值是 %d 和 %d\n",num1,num2);
}
void increment(int *ptr1,int *ptr2)
{
(*ptr1)++;
(*ptr2)++;
printf("\n 子函数中值 %d 和 %d\n",*ptr1,*ptr2);
}
引用调用示例请输入两个数,45 67递增前的值是 45 和 67_
递增后的值是 46 和 68
num1 num2
var1
45 67
var2
子函数中的值是 46 和 68
46
FF23 FF05
68
FF23 FF05
num1 num2
45 67
FF23 FF05
FF23 FF05
ptr2
FF45 FF51
调用前为 45
调用后为 46
将变量 num1的地址赋给形参,即指针
ptr1指向变量 num1
ptr1
调用前为 67
调用后为 68
将变量 num2的地址赋给形参,即指针
ptr2指向变量 num2
19
数组作为函数参数
在用数组作实参时,以传 址 方式调用函数,也就是说把实参数组的首地址赋给形参
实际上形参数组和实参数组为同一数组,共同拥有一段内存空间
20
数组作为参数示例 1
问题描述:
通过函数实现 5个学员成绩的排序。
#include <stdio.h>
#define N 5
void sort(float[]);
void main()
{
float grade[N];
int i;
printf("\n 输入 %d 个学员的成绩,\n",N);
for(i=0;i<N;i++)
scanf("%f",&grade[i]);
sort(grade);
printf("\n 排序后的成绩为,\n");
for(i=0;i<N;i++)
printf("%5.2f ",grade[i]);
printf("\n");
}
传递数组时不使用,&”
演示,示例 5
void sort(float a[N])
{
int i,j; float temp;
for(i=0;i<N;i++)
{
for(j=0;j<N-i-1; j++)
{
if(a[j] > a[j+1])
{
temp = a[j+1];
a[j+1] = a[j];
a[j] = temp;
}
}
}
}
21
问题描述:
通过函数实现求 5个数中的最大值。
#include <stdio.h>
int find_larg(int *);
void main()
{
int arr1[5];
int i,larg_num;
printf("\n 请输入 5 个不同的值,存储在一个数组中 \n");
for (i = 0; i <= 4; i++)
{
scanf("%d",&arr1[i]);
}
larg_num = find_larg(arr1);
printf("\n 最大的数是,%d\n ",larg_num);
}
数组作为参数示例 2
演示,示例 6
int find_larg(int *ptr)
{
int high = *ptr,i;
ptr++;
for (i = 1; i <=4; i++)
{
if (high < *ptr)
high = *ptr;
ptr++;
}
return high;
}
22
总结 2-1
根据变量的作用域可以将变量划分为:局部变量和全局变量
根据变量的存储类型(决定生存期)将变量划分为,自动变量、寄存器变量、静态变量、外部变量
静态局部变量的生存期为整个源程序,但其作用域为定义该变量的函数
静态全局变量的生存期为整个源程序,其作用域为定义该变量的源文件
23
总结 2-2
采用传值调用方式时,在被调用函数中改变形参的值,只是改变其副本值,而不会影响调用函数中实参值
采用 引用 调用方式时,传递的是变量的地址值,
这样在被调函数中,对形参的操作实际上操作的是实参本身
数组作为函数传递时,实际 采用引用调用方式