C语言二级辅导(函数ppt)

发布于:2021-07-26 23:32:54

函数定义和调用

函数的定义方法 函数类型和返回值

·函数原型、函数名、形式参数、函数返回值、函数体 ----函数执行过程的描述 ·不同类型函数定义、缺省类型、空类型

掌握 理解

函数传值调用

·形参、实参及其参数单向传递
·函数原型及作用 ·用户定义函数说明 ·系统库函数说明---用头文件包含 ·传值调用和传址调用 ·数组名作为函数参数 ·递归函数的定义和调用 ·递归函数的执行过程

掌握
理解 理解 理解 掌握 理解 知道 理解

函数说明
函数参数类型和函 数的传址调用 函数嵌套调用和递 归调用

2012-9-6

1

内容提要
? ? ? ? ?

函数定义、函数调用、函数原型、函数返回值 – 难点:函数的参数传递与返回值 全局变量、自动变量、静态变量、寄存器变量 – 难点:变量的作用域与存储类型 程序调试 结构设计与模块化 Larry 代码风格问题 Curly
Moe

2012-9-6

2

程序设计的艺术
结构化程序设计有两大最高级的艺术 – 算法设计艺术 – 结构设计艺术 ? C语言为程序的结构提供了两样武器 – 函数和模块 ? 函数(function)是结构设计的最基本单位 – “一个程序应该是轻灵自由的,它的子过程就象
?

串在一根线上的珍珠。”
?

Geoffrey James的《编程之道》

2012-9-6

3

数学函数(1)

y ? f (x)
自变量 因变量 函数名
2012-9-6 4

数学函数(2)
y ? 2x ? 3x ? 5
2

一个自变量,一个因变量

z ? ax ? by
n

m

?c

两个自变量,一个因变量

2012-9-6

5

数学函数(3)
? y1 ? ? 2 ? ? ? y2 1 ? ? ? ? ? y3 ? ? 8 ? ? ? ? y4 ? ?32 ? ?
因变量
2012-9-6

5 6 5 ?5

?3 6 ?2 ?3

8 ? ? 10 ? 4 ? ? 9 ?

? x1 ? ? ? x2 ? ? ? x3 ? ? ? ? x4 ? ? ?
自变量
6

Y ? AX

数学函数(4)

y ?
一个变量 二个变量

f (x)
自变量 与 因变量 的关系 一个变量 二个变量 …… N个变量
7

……
N个变量
2012-9-6

数学函数(5)

关系

集合A 集合B
2012-9-6 8

程序设计中的函数
?

程序设计中的函数不局限于计算 – 计算类,如打印阶乘表的程序…… – 判断推理类,如排序、查找……

2012-9-6

9

用函数解决问题的要点
?

分而治之 – 函数把较大的任务分解成若干个较小的任务,并提炼出
公用任务

?

复用 – 程序员可以在其他函数的基础上构造程序,而不需要从
头做起

?

信息隐藏 – 设计得当的函数可以把具体操作细节对程序中不需要知
道它们的那些部分隐藏掉,从而使整个程序结构清楚 Larry Curly Moe

2012-9-6

10

C中的函数(Function)
?

说明:
?一个源程序文件由一个或多个函数组成。

?一个C程序由一个或多个源程序文件组成。
?C程序的执行从main函数开始,调用其他函数后流程
回到main函数,在main函数中结束整个程序运行。

?所有函数都是*行的,即函数定义时是互相独立的,
一个函数并不从属于另一个函数。

2012-9-6

11

函数的分类
标准函数,即库函数 ? 用户自定义函数
?

2012-9-6

12

函数定义(definition)
返回值类型 函数名(类型 参数1, 类型 参数2, …… ) { 函数的返回值是通过 函数体 函数中的 return return 表达式; 语句获得的。 } ? 如果没有参数,则应该用void注明 ? 如果不需要返回值,则应该用void定义返回值类型 – 返回值类型与return语句配合 ? 当函数执行到return语句时,就中止函数的执行,返回到 调用它的地方 ? 函数内部可以定义只能自己使用的变量,称内部变量。 – 参数表里的变量也是内部变量
?
2012-9-6 13

函数参数
?

函数参数: – 形参( 形式参数 ):
?

在定义函数时,定义函数名后面括号中的变量名 在主调函数中调用一个函数,调用函数名后面括号 中的参数(或表达式)

– 实参( 实际参数 ):
?

2012-9-6

14

函数名命名规则
在Linux/Unix*台 – *惯用function_name ? 本书采用Windows风格函数名命名 – 用大写字母开头、大小写混排的单词组合而成 – FunctionName ? 变量名形式 – “名词”或者“形容词+名词” – 如变量名oldValue与newValue等 ? 函数名形式 – “动词”或者“动词+名词”(动宾词组) – 如函数名GetMax()等
?
2012-9-6 15

对函数接口加以注释说明
/* 函数功能:实现××××功能 函数参数:参数1,表示××××× 参数2,表示××××× 函数返回值: ××××× */ 返回值类型 函数名(参数表) { 函数体 return 表达式; }
2012-9-6 16

例计算两个整数的*均数
/* 函数功能: 计算*均数 函数入口参数: 整型x,存储第一个运算数 整型y,存储第二个运算数 函数返回值: *均数 */ int Average(int x, int y) { int result; result = (x + y) / 2; return result; }
2012-9-6 17

函数调用(call)
单向值传递 ? 调用函数时,必须提供所有的参数 – printf和scanf是采用变长变量表定义的函数,所以
?

变量的个数不固定。
?

提供的参数个数、类型、顺序应与定义时相同
实际参数 形式参数

2012-9-6

18

例5.1b 使用了Average函数的main()
main() { int a = 12; int b = 24; int ave;
main() { int a = 12; int b = 24; int ave; ave = Average(a, b); } int Average(int x, int y) { int result; result = (x + y) / 2; return result; 数据传递 执行顺序

printf(……);
}

ave = Average(a, b); printf("Average of %d and %d is %d.\n", a, b, ave);

}
2012-9-6 19

函数调用(call)
?

有返回值时 – 放到一个数值表达式中
?



返回值 = 函数名(实参表列);

c = max(a,b); – 作为另一个函数调用的参数
?



c = max(max(a,b),c); printf("%d\n", max(a,b));
?

无返回值时 – 函数调用表达式
?

函数名(实参表列);

如 display(a,b);

2012-9-6

20

函数原型(prototype)
?

调用一个函数之前,先要对其返回值类型、 函数名和参数进行声明(declare)
– 有助于编译器进行类型检查

?

声明时不要省略参数以及返回值的类型

2012-9-6

21

#include <stdio.h>

/*
函数功能: 计算*均数 函数入口参数: 整型x,存储第一个运算数 整型y,存储第二个运算数 函数返回值: *均数 */ int Average(int x, int y) { int result; result = (x + y) / 2; return result; }

例5.1

main() { int a = 12; int b = 24; int ave = Average(a, b); printf("Average of %d and %d is %d.\n", a, b, ave); }2012-9-6 22

#include <stdio.h> int Average(int x, int y); /*声明Average()函数*/

例5.1

main() { int a = 12; int b = 24; int ave = Average(a, b); printf("Average of %d and %d is %d.\n", a, b, ave); }

/*
函数功能: 计算*均数 函数入口参数: 整型x,存储第一个运算数 整型y,存储第二个运算数 函数返回值: *均数

*/ int Average(int x, int y) { int result; result = (x + y) / 2; return result; 2012-9-6 }

23

函数的嵌套调用
在被调函数中,又调用了函数----嵌套调用

main() { ① … … a(); ⑦ }
2012-9-6

a 函数 ③ { ② b(); … ⑥ ⑤ return; }

b函数 { … ④ … return; }
24

递归(Recursion)函数
函数直接或间接调用自己为递归 ? 阶乘函数的递归实现()
?

unsigned long Factorial(unsigned int n) { if (n < 0) printf("data error!"); else if (n==0 || n==1) return 1; else return n * Factorial(n-1); }
2012-9-6 25

2012-9-6

26

6. 写出下列程序的输出结果________ ? #include <stdio.h> ? long fac( int n ) ? { ? if ( n==1 ) return 1; ? return n*fac(n-1); ? } ? main() ? { ? printf( “5!=%ld\n”, fac(5) ); ? } 答案: 【5!=120】
?
2012-9-6 27

参数传递
传值 ? 传地址
?

2012-9-6

28

“值传递”举例
main() /*将一整数乘以10后显示出来*/ 在内存num与n {int num=5,result; 是两个不同的 result=mult10(num); 存储单元,如 printf(“result=%d ”,result); 果同名呢? printf(“num=%d ”,num);} int mult10(n) “值传递”是单向传 int n; 调用mult10时: 递 返回时: {n*=10; return(n);} 实参变量num的值 num
复制到
2012-9-6

新分配的形参单元 n

n

29

数组名作函数的参数 (地址传递)
对一组整形数据排序的函数: void sort(一维数组,int n) { 用某种算法对该数组排序 } void sort(int s[],int n) C语言允许一维数组作 形参时,可不定义大小 数据个数

{
用某种算法对该数组排序

发生调用时,实参数组 的首地址传给形参数组 ,这样实参数组和形参 数组共用同一段内存单 元,对形参数组的操作 就是对实参数组的操作
30

} 2012-9-6

数组名作函数的参数 (程序)
void sort(int s[],int n) { int j,t,k; main()

for(j=0;j<n-1;j++)

for( k=j+1;k<n;k++) 发生调用时对s数组的排序, sort(a,10); if(s[j]<s[k]) 就是对a数组的排序 for(j=0;j<10;j++) {t=s[j];

{int j,a[]={60,70,55,89,90,100 ,67,88,76,95};

s[j]=s[k];
s[k]=t;}
2012-9-6

printf(“%d,”,a[j]);
}
31

函数间的参数传递
?在函数被调用时才分配形参的存储单元 ?实参可以是常量、变量或表达式 ?实参类型必须与形参相符 ?单个变量传递时是传递参数值,即单向传递 ?数组作为参数时的情况:

*数组元素作实参,与单个变量一样,是“值传递” *数组名作参数,形、实参数都应是数组名,类型要 一样,传送的是数组首地址,是“地址传递”

2012-9-6

32

变量的作用域
指在源程序中定义变量的位置及其能被读写访问的 范围 ? 分为 – 局部变量(Local Variable) – 全局变量(Global Variable )
?

2012-9-6

33

局部变量
局部变量 – 在语句块内定义的变量 – 形参也是局部变量 ? 特点 – 定义时不会自动初始化,除非程序员指定初值 – 进入语句块时获得内存,仅能由语句块内语句访问,
?

退出语句块时释放内存,不再有效 – 并列语句块各自定义的同名变量互不干扰

2012-9-6

34

全局变量
全局变量 – 在所有函数之外定义的变量 ? 特点 – 在程序中定义它的位置以后都有效 – 在定义点之前或在其他文件中引用,应该进行如下声明:
?

extern 类型名 变量名; – 从程序运行起即占据内存,程序运行过程中可随时访问, 程序退出时释放内存 – 使函数之间的数据交换更容易,也更高效
? ?

但是并不推荐使用,尽量少用 因为谁都可以改写全局变量,所以很难确定是谁改写了它

2012-9-6

35

#include <stdio.h> int global; /*定义全局变量*/ void GlobalPlusPlus(void);

例5.7

main() { global = 1; printf("Before GlobalPlusPlus(), it is %d\n", global); GlobalPlusPlus(); printf("After GlobalPlusPlus(), it is %d\n", global); } /* 函数功能: 对全局变量global加1,并打印加1之前与之后的值 Before ++, it is 1 函数入口参数: 无 After ++, it is 2 函数返回值: 无 After GlobalPlusPlus(), it is 2 */ void GlobalPlusPlus(void) { printf("Before ++, it is %d\n", global); global++; printf("After ++, it is %d\n", global); }
2012-9-6 36

Before GlobalPlusPlus(), it is 1

#include <stdio.h> void GlobalPlusPlus(void);

例5.8

main() { int global = 1; printf("Before GlobalPlusPlus(), it is %d\n", global); GlobalPlusPlus(); printf("After GlobalPlusPlus(), it is %d\n", global); } /* 函数功能: 对局部变量global加1,并打印加1之前与之后的值 Before ++, it is 1 函数入口参数: 无 After ++, it is 2 函数返回值: 无 After GlobalPlusPlus(), it is 1 */ void GlobalPlusPlus(void) { int global = 1; printf("Before ++, it is %d\n", global); global++; printf("After ++, it is %d\n", global); }
2012-9-6 37

Before GlobalPlusPlus(), it is 1

变量的存储类型
指数据在内存中存储的方式 ? 即编译器为变量分配内存的方式,它决定变量的生存期 ? 动态存储 – 根据需要临时分配存储空间,离开即释放 ? 静态存储 – 在程序运行期间分配固定的存储空间不释放
?

程序区 静态存储区
2012-9-6

全局变量、 静态变量 形参、自动变 量、函数调用 的现场等

动态存储区

38

自动变量 (auto )
?

“自动”体现在 – 进入语句块时自动申请内存,退出时自动释放内存 标准定义格式
auto 类型名 变量名;

?

– 动态局部变量 – 缺省的存储类型 – 不初始化时,值是不确定的

2012-9-6

39

静态变量(static)
一般的内部变量 – 在函数退出后失效,再次进入函数,变量值重新初始化 ? 静态变量 – 在变量类型前面用static修饰
?
?

static int i;

– 变量的值可以保存到下次进入函数,使函数具有记忆功能

2012-9-6

40

静态变量
?

静态变量和全局变量都是静态存储类型 – 自动初始化为0 – 从静态存储区分配,生存期为整个程序运行期间 – 但作用域不同

程序区 静态存储区
2012-9-6

全局变量、 静态变量 形参、自动变 量、函数调用 的现场等

动态存储区

41

#include <stdio.h> void Func(void); main() { int i;
for (i=0; i<10; i++) { Func(); } }

例5.9
Func() Func() Func() Func() Func() Func() Func() Func() Func() Func() was was was was was was was was was was called called called called called called called called called called 1 1 1 1 1 1 1 1 1 1 time(s). time(s). time(s). time(s). time(s). time(s). time(s). time(s). time(s). time(s).

/* 函数功能: 打印被调用的次数 函数入口参数: 无 函数返回值: 无 */ void Func(void) { int times = 1; /*自动变量*/ }

printf("Func() was called %d time(s).\n", times++);
2012-9-6 42

#include <stdio.h> void Func(void); main() { int i;
for (i=0; i<10; i++) { Func(); } }

例5.9
Func() Func() Func() Func() Func() Func() Func() Func() Func() Func() was was was was was was was was was was called called called called called called called called called called 1 time(s). 2 time(s). 3 time(s). 4 time(s). 5 time(s). 6 time(s). 7 time(s). 8 time(s). 9 time(s). 10 time(s).

/* 函数功能: 打印被调用的次数 函数入口参数: 无 函数返回值: 无 */ void Func(void) { static int times = 1; /*静态局部变量*/ }

printf("Func() was called %d time(s).\n", times++);
2012-9-6 43

寄存器变量(register)
寄存器 – CPU的内部容量很有限、但速度极快的存储器 ? 使用频率比较高的变量声明为register ,可以 使程序更小、执行速度更快 – register 类型名 变量名; – register int i; ? 现代编译器有能力自动把普通变量优化为寄存器变 量,并且可以忽略用户的指定,所以一般无需特别 声明变量为register
?

2012-9-6

44

模块化程序设计方法
?

什么时候需要模块化? – 某一功能,如果重复实现3遍以上,即应考虑模块化,将
它写成通用函数,并向小组成员发布

?

要尽可能复用其它人的现成模块。拿来拿去主义。

2012-9-6

45

复用
?

复用是高质量软件开发的基本方法之一 – 拿来拿去主义,指利用现成的东西 – 不是人类懒惰的表现,而是智慧的表现 – 技术开发活动和管理活动中的任何成果都可以被复用,
如思想、方法、经验、程序、文档等 – 构建新的软件系统可以不必每次从零做起,直接使用已 有的经过反复验证的软构件,组装或加以合理修改后成 为新的系统,提高软件生产率和程序质量 – 一般要靠日积月累才能建设可以被复用的软件库
?

前期投入多,缺乏*期效益,大部分公司都注重*期效益,是 为了生存,所以软件复用对公司来说不是最高优先级
46

2012-9-6

2. 程序调试题2(C_3_2.C) ? 调试要求:下列程序有3处错误,请按题中的 功能要求,在不改变程序结构(不增加、删除 语句,不调整语句顺序)的情况下调试并修改 该程序(在所修改语句后加/*******/字样的注 释),使其运行能得到正确的结果。将结果( 包括C_3_2.c文件和C_3_2.exe文件)保存到目 录C:\KS\中。 ? 功能说明:以下程序中函数str_to_upper将字符 串中的小写字母转换为大写字母,主函数调用 此函数及输入输出数据,用户通过键盘输入计 算所需的数据。 2012-9-6
?

47

原程序(见C:\KS\C_3_2.C): #include <stdio.h> void str_to_upper( char *s ) { while ( *s == '\0' ) { if ( *s>='a' || *s<='z' ) *s = *s - 'A' + 'a'; s++; } }

原程序(见C:\KS\C_3_2.C): void main() { char str[80]; gets( str ); str_to_upper( str ); puts( str ); }

2012-9-6

48

?

计算

p ?

k! ( m ? k )!

复用Factorial函数的代码 unsigned long Factorial(unsigned int number); main() { unsigned int m, k; unsigned long p; printf("Please input m, k:"); scanf("%u, %u", &m, &k); p = Factorial(k) / Factorial (m-k); printf("p=%lu\n", p); }
2012-9-6 49


相关推荐

最新更新

猜你喜欢