页数:51页文件大小:804.9 KB来源: C语言程序设计ppt课件
本课件讲解C语言的函数与模块化程序设计,先介绍模块化思想、C程序的模块化结构与函数分类,再说明函数定义的两种风格、返回值与函数调用形式、函数原型声明与嵌套调用,然后重点对比值传递与地址传递,最后系统梳理变量的作用域与生存期以及auto、register、static、extern四种存储类型。
Chapter 6 函数(Functions)
模块化程序设计
每个模块可视为一个函数:给定输入、产生输出。
C是模块化程序设计语言:一个C程序由若干源文件组成,每个源文件包含预处理命令、数据说明与若干函数(Function1 ~ Function n)。
函数分类
使用库函数应注意:1、函数功能;2、函数参数的数目、顺序及各参数意义和类型;3、函数返回值意义和类型;4、需要使用的包含文件。
函数定义一般格式
函数类型 函数名(形参类型说明表) { 说明部分 语句部分 }int max(int x, int y) { int z; z = x>y ? x:y; return(z); } void printstar(void) { printf("**********\n"); }旧式写法:int max(x, y) int x, y; { ... }。函数类型缺省为 int;空函数写作 void dummy(void){ };C语言不允许函数嵌套定义。
例:定义函数 min 求三个整数的最小值
int min(int x, int y, int z) { int t; t = x<y ? x:y; return(t<z ? t:z); }判断定义合法性:
void func1(a,b,c) — 缺形参类型说明,非法float func2(float a, float b){ float a,b,c; ... } — 形参 a、b 在函数体内重复定义,非法返回语句:return(expression); 或 return expression; 或 return;
int max(float x, float y) { float z; z = x>y ? x:y; return(z); } 函数调用格式:函数名(实参表)
printstar();printf("Hello,World!\n");m = max(a,b)*2;printf("%d", max(a,b));m = max(a, max(b,c));对被调用函数的要求:必须是已存在的函数;库函数用 #include <*.h>;用户自定义函数需作函数原型说明。
函数原型声明:函数类型 函数名(形参类型[形参名], ...);
#include <stdio.h> float add(float x, float y); void main() { float a, b, c; scanf("%f%f", &a, &b); c = add(a, b); printf("sum is %f\n", c); } float add(float x, float y) { float z; z = x + y; return(z); }#include <stdio.h> float add(float x, float y) { float z; z = x + y; return(z); } void main() { float a, b, c; scanf("%f,%f", &a, &b); c = add(a, b); printf("sum is %f", c); }被调函数定义出现在主调函数之前,可省略原型说明。思考:main 中调用 func(); 而 void func(void){ } 定义在其后,须补写 void func(void); 说明。
函数嵌套调用:C语言不允许嵌套定义,但允许嵌套调用。
void main() { ... sum = add(a, b); ... } int add(int x, int y) { int z; z = square(x+y); return z; } int square(int x) { return x*x; }调用过程:main 调用 add(保存现场)→ add 调用 square → 返回 add → 返回 main。
例:输入三个整数,输出最大值与最小值的差
#include <stdio.h> int dif(int x, int y, int z); int max(int x, int y, int z); int min(int x, int y, int z); void main() { int a, b, c, d; scanf("%d%d%d", &a, &b, &c); d = dif(a, b, c); printf("Max-Min=%d\n", d); } int dif(int x, int y, int z) { return max(x,y,z) - min(x,y,z); }调用关系:main 调 dif,dif 分别调 max 与 min。
形参与实参
int max(int x, int y); void main() { ... c = max(a, b); ... } int max(int x, int y) { int z; z = x>y ? x:y; return(z); }说明
p = func(i=3, i); p = func(i, i=3); int func(int a, int b) { if(a>b) c=1; else if(a==b) c=0; else c=-1; return(c); }#include <stdio.h> int sum(int a, int b); int factorial(int n); void main() { int n1, n2, a; scanf("%d %d", &n1, &n2); a = sum(n1, n2); printf("%d!+%d!=%d", n1, n2, a); } int sum(int a, int b) { int c1, c2; c1 = factorial(a); c2 = factorial(b); return(c1 + c2); } int factorial(int n) { int rtn = 1, i; for (i = 1; i <= n; i++) rtn *= i; return(rtn); }参数传递方式——值传递
#include <stdio.h> void swap(int x, int y) { int temp; temp = x; x = y; y = temp; } void main() { int a = 7, b = 11; printf("a=%d,b=%d\n", a, b); swap(a, b); printf("swapped:\n"); printf("a=%d,b=%d\n", a, b); }输出:a=7,b=11 / swapped: a=7,b=11。形参 x、y 得到的是 a、b 的副本,交换只发生在副本上。
内存示意:main 中 a(2000)=7、b(2002)=11;swap 中 x(2008)=7、y(200A)=11 为 COPY,temp 交换后 x=11、y=7,但 main 中 a、b 不变,故输出两行均为 a=7, b=11。
#include <stdio.h> void swap(int x, int y) { int temp; temp = x; x = y; y = temp; } void main() { int a[2] = {7, 11}; swap(a[0], a[1]); printf("a[0]=%d\na[1]=%d\n", a[0], a[1]); }数组元素作函数实参仍属于值传递,交换不影响数组元素本身。
数组元素 a[0]=7、a[1]=11 作为实参,其值复制到形参 x(2008)、y(200A),temp 交换后 x=11、y=7;main 中数组 a 的内容不变,仍为 7、11。
参数传递方式——地址传递
说明:C语言中所有参数传递本质上都是值传递(All argument-passing is strictly by value),地址传递是把地址值传给形参。
数组名作函数参数——地址传递
#include <stdio.h> void swap(int x[2]) { int temp; temp = x[0]; x[0] = x[1]; x[1] = temp; } void main() { int a[2] = {7, 11}; swap(a); printf("a[0]=%d\na[1]=%d\n", a[0], a[1]); }调用时把数组 a 的首地址 2000 传给形参 x,x 与 a 指向同一段内存,交换后 a[0]=11、a[1]=7。
实参 a 的首地址为 2000,形参 x 得到该地址(COPY 的是地址值);x[0]、x[1] 即 a[0]、a[1]。交换后内存中 a[0]=11、a[1]=7,实现双向传递。形参用数组定义 int x[ ] 形式,是地址变量。
#include <stdio.h> void get_sum_row(int x[][3], int result[], int row, int col) { int i, j; for (i = 0; i < row; i++) { result[i] = 0; for (j = 0; j < col; j++) result[i] += x[i][j]; } } void main() { int a[2][3] = {3, 6, 9, 1, 4, 7}; int sum_row[2], row = 2, col = 3, i; get_sum_row(a, sum_row, row, col); for (i = 0; i < row; i++) printf("The sum of row[%d]=%d\n", i+1, sum_row[i]); }结果:第1行 18、第2行 12。形参数组最左一维大小可省略,其余各维必须相同(int x[][3])。
概述:变量是对程序中数据存储空间的抽象。程序中使用变量名对内存操作;编译或函数调用时为其分配内存单元。
void main() { int a; a = 10; printf("%d", a); } 变量存储方式
内存用户区划分:程序区、静态存储区(永久性变量)、动态存储区(暂时变量)。
变量的属性
应尽量少使用全局变量:全局变量在程序全部执行过程中占用存储单元;降低函数的通用性、可靠性、可移植性;降低程序清晰性,容易出错。
变量的存储类型
[存储类型] 数据类型 变量表; int sum; auto int a, b, c; register int i; static float x, y;外部型 extern:extern int a, b;
错误写法:extern int a = 2;(说明时不能初始化)。
自动型 auto:auto int a, b, c; 等价于 int a, b, c;
寄存器型 register:register int a, b;
void main() { register int i, sum; for (i = 0, sum = 0; i <= 100; i++) sum += i; printf("Sum=%d\n", sum); }静态型 static:static int a, b[5];
| 项目 | 静态存储 | 动态存储 |
|---|---|---|
| 存储方式 | 程序整个运行期间分配固定空间 | 函数调用开始至结束 |
| 赋初值 | 编译时赋初值,只赋一次 | 每次函数调用时自动赋初值 |
| 未赋初值 | 0 或空字符 | 不确定 |
| 存储区 | 静态存储区 | 动态区、寄存器 |
| 作用域 | 局部变量、外部变量 | 定义变量的函数或复合语句内 |
| 存储类别 | 局部 static、外部 static、外部变量 | auto、register、形参 |
| 适用范围 | 本文件或所有文件 | 本函数内 |
float f1(int a) { int b, c; ... } char f2(int x, int y) { int i, j; ... } void main() { int m, n; ... } main 函数中定义的变量只在 main 中有效,形参也是局部变量,不同函数可使用同名变量。
int a = 3, b = 5; void main() { void swap(void); printf("a=%d,b=%d\n", a, b); swap(); printf("a=%d,b=%d\n", a, b); } int temp; void swap(void) { temp = a; a = b; b = temp; }全局变量自动初始化成 0,采用静态存储,作用域可扩展;a、b 与 temp 均为全局,swap 直接操作它们即可完成交换。
void main() { int x = 1; void prt(void); { int x = 3; prt(); printf("2nd x=%d\n", x); } printf("1st x=%d\n", x); } void prt(void) { int x = 5; printf("3th x=%d\n", x); }输出:3th x=5 / 2nd x=3 / 1st x=1。内层复合语句中的 x=3 屏蔽外层 x=1,prt 中的 x=5 又是另一个变量。
void sub(); void main() { int a, b; a = 3; b = 4; printf("main:a=%d,b=%d\n", a, b); sub(); printf("main:a=%d,b=%d\n", a, b); } void sub() { int a, b; a = 6; b = 7; printf("sub:a=%d,b=%d\n", a, b); }输出:main:a=3,b=4 / sub:a=6,b=7 / main:a=3,b=4。动态存储区按栈方式工作,各函数局部变量互不干扰。
int a = 3, b = 5; int max(int a, int b) { int c; c = a>b ? a:b; return(c); } void main() { int a = 8; printf("max=%d\n", max(a, b)); }输出 max=8。main 中的局部 a=8 屏蔽全局 a=3,b 仍取全局变量 5,故 max(8,5)=8。
void prt(); int i; void main() { for (i = 0; i < 5; i++) prt(); } void prt(void) { for (i = 0; i < 5; i++) printf("%c", '*'); printf("\n"); }输出:*****(仅一行)。prt 中的循环把全局 i 修改为 5,main 的循环条件失效,这是外部变量的副作用。
int a; main() { ... f2(); ... f1(); ... } f1() { auto int b; ... f2(); ... } f2() { static int c; ... } 调用顺序:main → f2 → f1 → f2 → main;a 全程存在,b 随 f1 调用生灭,c 常驻静态区。
void increment(void) { int x = 0; x++; printf("%d\n", x); } void increment(void) { static int x = 0; x++; printf("%d\n", x); } static 局部变量在编译时赋初值一次,值具有继承性,适合记录调用次数或累加结果。
int a = 10, b = 0; void func1() { int a = 25, b = 50; b /= a + 5; printf("a= %d, b= %d\n", a, b); } void func2() { printf("a= %d, b= %d\n", a, b += 5); } void main() { int b = 10; printf("a+5= %d, b= %d\n", a + 5, b); func1(); func2(); }运行结果:a+5=15, b=10 / a=25, b=1 / a=10, b=5。func1 内 a、b 为局部,func2 内 a、b 为全局。
int mathfun(int fst) { static int thd = 5; int sec = 0; sec += 1; thd += 1; return(fst + sec + thd); } void main() { int n = 4, num = 0; for (num = 1; num <= 3; num++) printf("%d ~ %d\n", num, mathfun(n)); }sec 每次调用重置为 1,thd 依次累加为 6、7、8,返回 4+1+thd,故输出 A:1 ~ 11、2 ~ 12、3 ~ 13。
int i = 1; void main() { static int a; register int b = -10; int c = 0; printf("-----MAIN------\n"); printf("i:%d a:%d b:%d c:%d\n", i, a, b, c); c = c + 8; other(); printf("-----MAIN------\n"); printf("i:%d a:%d b:%d c:%d\n", i, a, b, c); i = i + 10; other(); } void other() { static int a = 2; static int b; int c = 10; a = a + 2; i = i + 32; c = c + 5; printf("-----OTHER------\n"); printf("i:%d a:%d b:%d c:%d\n", i, a, b, c); b = a; }输出:MAIN i:1 a:0 b:-10 c:0 → OTHER i:33 a:4 b:0 c:15 → MAIN i:33 a:0 b:-10 c:8 → OTHER i:75 a:6 b:4 c:15。
注:原课件输出行中 a、b 之间的分隔符显示为 \b,此处按格式串 i:%d a:%d b:%d c:%d 规范呈现。
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; ... } extern char c1, c2; 全局变量自动初始化成 0,采用静态存储;用 extern 说明可扩展其作用域。
void main() { void gx(), gy(); extern int x, y; printf("1: x=%d\ty=%d\n", x, y); y = 246; gx(); gy(); } void gx() { extern int x, y; x = 135; printf("2: x=%d\ty=%d\n", x, y); } int x, y; void gy() { printf("3: x=%d\ty=%d\n", x, y); }输出:1: x=0 y=0 / 2: x=135 y=246 / 3: x=135 y=246。
写法一(值传递,交换无效)
void swap(int x, int y) { int t; t = x; x = y; y = t; } void main() { extern int a, b; swap(a, b); printf("a=%d b=%d\n", a, b); } int a = 13, b = -8;写法二(直接操作全局变量,交换有效)
void swap() { int t; t = a; a = b; b = t; } void main() { extern int a, b; swap(); printf("a=%d b=%d\n", a, b); } int a = 13, b = -8; int global; extern int global; extern int global; void func1() static int number; static int number; { global = 1; x = 1; } void func2() float x; { number = 2; void func3() global = 2; } { number = 3; global = 3; printf(...); }主文件中用 extern int global;、extern float x; 说明后再调用 func1、func2、func3,即可引用其他文件定义的外部变量;static 全局变量 number 则不能扩展到其他文件。
本章小结
下载地址:{{downurl}}
{{{a}}}
{{#b}}{{{b}}}
{{/b}} {{/title}} {{#nolog}}登陆注册
{{/nolog}} {{#djsx}}点我刷新
{{/djsx}} {{#gocz}} {{/gocz}} {{#ffqr}} {{/ffqr}}