第5章 函 数
目 录 函数概述 函数定义的一般形式 函数的调用、参数和返回值 局部变量和全局变量 变量的存储类型 内部函数和外部函数 目 录 函数概述 函数定义的一般形式 函数的调用、参数和返回值 局部变量和全局变量 变量的存储类型 内部函数和外部函数 C语言程序设计 - 第5章 函数
函数 (Function) C语言用函数实现程序模块化 一个程序由一个或多个源程序文件组成 一个源程序文件由一个或多个函数组成 C程序的执行从main函数开始,并回到main函数结束 函数之间可以相互调用,或调用自身 不能调用main函数 函数之间相互独立,不存在从属关系 C语言程序设计 - 第5章 函数
函数定义的一般形式 函数定义形式 返回类型、参数、函数体内容都可没有 返回类型 函数名(参数声明) { 声明部分 语句 } dummy(){} /* does nothing & returns nothing */ C语言程序设计 - 第5章 函数
函数定义形式的说明 关于“返回类型” 关于“参数声明” 关于“声明部分” 指函数返回值的类型 若省略此项,则认为返回类型是int 若无返回值,则定义返回类型为void 关于“参数声明” 类型 形参名, 类型 形参名, ... 关于“声明部分” 指变量、函数的声明 C语言程序设计 - 第5章 函数
函数定义举例 int max(int x, int y) { int z; z = x>y?x:y; return z; } int min(int x, int y) return x<y?x:y; C语言程序设计 - 第5章 函数
函数的调用、参数和返回值 函数的参数 函数的返回值 函数的调用 形参和实参 参数传递 函数调用的形式 函数的声明和函数原型 函数的嵌套调用和递归调用 C语言程序设计 - 第5章 函数
函数的参数 (Arguments) 形式参数和实际参数 举例 形参:定义函数时,函数名后()中的参数 实参:调用函数时,函数名后()中的参数 实参可以是常量、变量、表达式、函数调用 实参和形参必须类型相同或赋值兼容 举例 int max(int x, int y)/*函数定义*/ { return x>y?x:y; } max(a, 3); /*函数调用*/ C语言程序设计 - 第5章 函数
参数传递 值传递 单向传递 实参和形参是不同的变量 实参对形参的数据传递是“值传递” 只能把实参的值传递给形参 不能把形参的值传递给实参 对形参的值所作的改变不能带回给实参 实参和形参是不同的变量 具有不同的存储空间 具有不同的生存期和作用域 C语言程序设计 - 第5章 函数
参数传递举例 (05-01.C) 4 1 1 4 1 4 x y a b void swap(int x, int y) { int t; t=x, x=y, y=t; } void main() int a=1, b=4; swap(a, b); x y 4 1 1 4 1 4 a b C语言程序设计 - 第5章 函数
return语句 形式 功能 形式一:return; 形式二:return expression; 函数返回语句 结束函数调用 如果需要,还可以带回函数返回值 C语言程序设计 - 第5章 函数
函数的返回值 (Return Value) 返回值的说明 函数返回值的类型在函数定义中指定 函数返回值通过函数中的return语句获得 函数需要返回值时,若缺少return语句,或return语句未带返回值,则返回一个不确定值 C语言程序设计 - 第5章 函数
函数的调用 一般形式 说明 函数名(实参表列) 即使没有实参,()也不能省略 多个实参之间用逗号分隔 实参与形参按顺序一一对应,类型应匹配 实参的求值顺序不确定,应避免对此敏感的调用形式 printf("%d,%d", i, i++); C语言程序设计 - 第5章 函数
函数调用的应用 函数语句 函数表达式 函数参数 说明 printf("%d\n", i); (c + d * max(a,b)) % e gcd(max(a,b), min(c, d)) 说明 函数调用可以看作同返回类型的表达式使用 同时,函数调用还完成了函数中定义的操作 C语言程序设计 - 第5章 函数
函数原型 (Prototype) 一般形式 举例 类型 函数名(类型1, 类型2, ...); 类型 函数名(类型1 形参1, 类型2 形参2, ...); 举例 int max(int, int); int max(int x, int y); void dummy(); /* 无参函数原型 */ void dummy(void); /* 同上 */ C语言程序设计 - 第5章 函数
函数的声明 (Declaration) 函数声明的形式即函数原型 在函数调用之前,应对函数进行声明 函数声明可以在主调函数的声明部分,也可以在函数外部 函数外部的声明,对所有主调函数都起作用,不需要在主调函数内再次声明 函数的定义也具有声明的作用 库函数的声明包括在头文件(*.h)里,不需在源程序里声明 C语言程序设计 - 第5章 函数
函数声明举例 (1) void main() { int max(int x, int y); /* 函数声明 */ int a, b, c; c = max(a, b); } int max(int x, int y) return x>y?x:y; C语言程序设计 - 第5章 函数
函数声明举例 (2) int max(int x, int y); /* 函数声明 */ void main() { /* 不需要再次声明int max(int, int) */ int a, b, c; c = max(a, b); } int max(int x, int y) { return x>y?x:y; C语言程序设计 - 第5章 函数
函数声明举例 (3) int max(int x, int y) /* 函数定义具有声明作用 */ { return x>y?x:y; } void main() { /* 不需要再次声明int max(int, int) */ int a, b, c; c = max(a, b); C语言程序设计 - 第5章 函数
函数的嵌套调用 调用一个函数的过程中,调用另一函数 main函数 结束 调用a函数 b函数 a函数 调用b函数 C语言程序设计 - 第5章 函数
函数的递归调用 一个函数直接或间接的调用它自身 必须有一定的条件判断语句,使得递归调用能够终止 f函数 调用f函数 f1函数 调用f2函数 C语言程序设计 - 第5章 函数
函数递归调用举例 Hanoi塔 (汉诺塔、河内塔、梵塔) C语言程序设计 - 第5章 函数
例1:Hanoi塔 解法 复杂度 N=1时,Hanoi(1)易解 若Hanoi(N-1)可解,则Hanoi(N)易解 Step1. N-1个盘子,借助3,从1移至2 Step2. 把最大的盘子从1移至3 Step3. N-1个盘子,借助1,从2移至3 复杂度 移动次数:2N-1 N=64,移动次数~1.84467E+19 C语言程序设计 - 第5章 函数
变量的作用域和生存期 作用域 生存期 变量有效的代码空间 变量在作用域才能被引用 变量可以分为局部变量和全局变量 变量有效的运行时间 变量在生存期内才存在 变量可以分为静态存储和动态存储 C语言程序设计 - 第5章 函数
局部变量 (Local Variables) 函数或复合语句内部定义的变量 说明 作用域为本函数或复合语句范围 不同函数内的局部变量可以重名,它们是不同的变量,作用域不同,不会相互干扰 函数形参也是局部变量的一种 若多个同名局部变量作用域重叠,则最内层复合语句中定义的局部变量有效 C语言程序设计 - 第5章 函数
局部变量举例 (1) float foo(int x) { int a, i, j; /* 局部变量 */ } void main() int a, b, c; /* 局部变量 */ ... ... /* 只能用在main内部 */ x,a,i,j 作用域 a,b,c 作用域 C语言程序设计 - 第5章 函数
局部变量举例 (2) void main() { int a, b, i; ... ... int c, i; c = a + b; i = a - b; } a,b,i 作用域 c,i作用域 此范围内复合语句 中定义的i有效 C语言程序设计 - 第5章 函数
全局变量 (Global Variables) 全局变量(外部变量) 函数之外定义的变量 说明 作用域从变量定义处到本源程序文件结束 全局变量可以被本文件的函数所共用 增加函数间传递数据的渠道 若全局变量与局部变量重名,则局部变量在作用域内屏蔽全局变量 应限制使用过多全局变量 C语言程序设计 - 第5章 函数
全局变量举例 int a=10, b=5, x, y; /* 全局变量 */ int max(int x, int y) { return x>y?x:y; } int c; /* 全局变量 */ void main() int a=8; c=max(a, b); /* 引用局部变量a */ 形参x,y 作用域 全局变量 a,b,x,y 作用域 全局变量 c作用域 局部变量 a作用域 C语言程序设计 - 第5章 函数
动态存储方式和静态存储方式 动态存储方式 静态存储方式 程序运行期间根据需要动态分配存储空间 函数形参、自动变量等 每次调用函数时,给该函数中的局部变量和形参分配存储空间,函数返回后释放空间 静态存储方式 程序运行期间分配固定的存储空间 全局变量全部存放在静态存储区中 C语言程序设计 - 第5章 函数
变量的存储类型 自动变量 auto 寄存器变量 register 静态变量 static 外部变量 extern
自动(auto)变量 auto变量 举例 局部变量,用auto关键字修饰 auto可以省略,是缺省的存储方式 自动分配和释放存储空间 int foo(int x) { auto int a, b, c=6; /* 定义自动变量a,b,c */ float f, g=0.1; /* 定义自动变量f,g */ } C语言程序设计 - 第5章 函数
寄存器(register)变量 register变量 举例 存放在CPU寄存器中,存取速度快 寄存器变量只能动态分配存储空间(寄存器) 只有自动变量和形参可以作为寄存器变量 举例 int foo(int x) { register int i; /* 定义寄存器变量i */ for(i=0; i<10000; i++)... /* i用于循环变量 */ } C语言程序设计 - 第5章 函数
静态(static)局部变量 静态局部变量 局部变量,用static关键字修饰 静态局部变量为静态存储,整个程序运行期间都不释放,其值不会丢失 在函数调用结束后,静态局部变量虽仍然存在,但已经不在变量的作用域内,所以其他函数不能引用它 静态局部变量在编译时赋初值,且只赋一次 若不对静态局部变量赋初值,则初值为0 C语言程序设计 - 第5章 函数
静态局部变量举例 i 1 2 x 2 a 2 b 1 c 6 5 4 3 f(x) 9 8 7 - int f(int a) { int b=0; static int c=3; b++; c++; return a+b+c; } void main() int x=2, i; for(i=0;i<3;i++) printf("%d\n",f(x)); i 1 2 x 2 a 2 b 1 c 6 5 4 3 f(x) 9 8 7 - C语言程序设计 - 第5章 函数
用extern声明外部变量 非静态外部变量 没有用static声明的外部变量 可以用extern声明外部变量,以扩展外部变量的作用域 可以在一个文件内声明外部变量,以在外部变量定义之前就可以使用 可以在多文件程序中声明外部变量,以在其他文件中引用某个文件中定义的外部变量 外部变量的定义一般放在所有函数之前 C语言程序设计 - 第5章 函数
非静态外部变量举例 (1) int max(int x, int y) { return x>y?x:y; } void main() extern A, B;/* extern声明外部变量 */ printf("%d", max(A, B)); } /* 在定义之前使用外部变量 */ int A=13, B=-8; /* 定义外部变量 */ C语言程序设计 - 第5章 函数
非静态外部变量举例 (2) /* file1.c */ /* 声明外部变量 */ extern A, B; void main() { int c; c=max(A, B); printf("%d", c); } /* file2.c */ /* 定义外部变量 */ int A=13, B=-8; int max(int x, int y) { int z; z=x>y?x:y; return z; } C语言程序设计 - 第5章 函数
用static声明外部变量 静态外部变量 举例 限制外部变量只能被本文件引用 静态外部变量不能被其他文件引用 /* file1.c */ static int A; main() { ... ... } /* file2.c */ extern int A; void foo(int n) { A = A * n; } 不能引用静态 外部变量A C语言程序设计 - 第5章 函数
变量的声明和定义 声明 (Declaration) 定义 (Definition) 举例 对变量的某些属性加以说明 定义一个新的变量,并分配存储空间 定义有声明的功能,但声明不一定都是定义 举例 void main() { extern A; /* 声明而非定义,声明A为已定义外部变量 */ ... ... } int A; /* 定义A为整型外部变量 */ C语言程序设计 - 第5章 函数
从作用域角度分类 局部变量 全局变量 自动变量 (离开函数,值就消失) 寄存器变量 (离开函数,值就消失) 自动变量 (离开函数,值就消失) 寄存器变量 (离开函数,值就消失) 形式参数 (可为自动或寄存器变量) 静态局部变量 (离开函数,值仍保留) 全局变量 静态外部变量 (只限本文件引用) 非静态外部变量 (允许其他文件引用) C语言程序设计 - 第5章 函数
从生存期角度分类 动态存储 静态存储 自动变量 (本函数内有效) 寄存器变量 (本函数内有效) 形式参数 (本函数内有效) 自动变量 (本函数内有效) 寄存器变量 (本函数内有效) 形式参数 (本函数内有效) 静态存储 静态局部变量 (本函数内有效) 静态外部变量 (本文件内有效) 非静态外部变量 (其他文件可以引用) C语言程序设计 - 第5章 函数
从存放位置角度分类 内存动态存储区 内存静态存储区 CPU中的寄存器 自动变量 形式参数 静态局部变量 静态外部变量 (本文件内有效) 静态外部变量 (本文件内有效) 非静态外部变量 (其他文件可以引用) CPU中的寄存器 寄存器变量 C语言程序设计 - 第5章 函数
变量作用域和生存期小结 † ‡ 变量存储类型 函数内 函数外 作用域 生存期 自动变量 形式参数 寄存器变量 静态局部变量 静态外部变量 † 非静态外部变量 ‡ †只限本文件 ‡其他文件也可以引用 C语言程序设计 - 第5章 函数
内部函数 定义形式 说明 举例 static 类型 函数名(形参表) 内部函数又称静态函数 内部函数只能在所在文件中使用 类似于静态外部变量的作用范围 举例 static int foo(int a, int b); C语言程序设计 - 第5章 函数
外部函数 定义形式 说明 举例 extern 类型 函数名(形参表) 可以在其他文件中调用 extern关键字在定义时可以省略 extern int foo(int a, int b); C语言程序设计 - 第5章 函数
各种变量和关键字用法总结 自动变量、形参、寄存器变量用法相同 所有外部变量都是静态存储的 static关键字的意义 寄存器变量存放在CPU中,但不影响用法 所有外部变量都是静态存储的 不管是不是static的外部变量 static关键字的意义 静态局部变量,表示“静态存储” 静态外部变量和函数,表示只能用于本文件 非静态外部变量和函数,表示其他文件可以引用,外部引用时用extern加以声明 C语言程序设计 - 第5章 函数
结束 The End 改编自白雪飞老师的 presentations, 感谢白老师! C语言程序设计 - 第5章 函数