Presentation is loading. Please wait.

Presentation is loading. Please wait.

第七章 函数及变量存贮类型 7.1 函数基础与C程序结构 7.2 函数的定义和声明 7.3 函数的调用 7.4 函数的嵌套与递归

Similar presentations


Presentation on theme: "第七章 函数及变量存贮类型 7.1 函数基础与C程序结构 7.2 函数的定义和声明 7.3 函数的调用 7.4 函数的嵌套与递归"— Presentation transcript:

1 第七章 函数及变量存贮类型 7.1 函数基础与C程序结构 7.2 函数的定义和声明 7.3 函数的调用 7.4 函数的嵌套与递归
第七章 函数及变量存贮类型 7.1 函数基础与C程序结构 7.2 函数的定义和声明 7.3 函数的调用 7.4 函数的嵌套与递归 7.5 变量的存贮类别

2 7.1 函数基础与C程序结构 7.1.1 C程序的结构化设计思想 图 7.1 C程序结构示意图

3 7.1.2 函数概述 在C程序设计中,函数是独立的C程序模块,它完成一个特定任务并可选择是否将一个值返回调用程序。在C语言中, 子程序被称为函数,它相应于其它高级语言中的过程(无返回值的子程序)和函数(通过函数名返回一个值的子程序)。一个C程序一般由多个函数组成,其中必须有一个且仅有一个名为main的主函数,其余为被main函数或其它函数调用的函数,无论main函数位于程序中什么位置, C程序总是从main函数开始执行。

4 main函数可调用其它函数来实现所需的功能。 被main函数调用的函数分为两类:一类是由系统提供的标准库函数,例如, 标准输入输出函数(scanf, printf, getche, putchar, …)、数学计算函数(sin, cos, fabs, sqrt, …)、 数据格式转换函数(atoi,atof,sscanf,sprintf, …)、 字符串处理函数(strlen,strcpy,strcmp, …)和文件读写函数(fread, fwrite, fopen, …)等。 这类函数可以由用户程序直接调用; 另一类是用户在自己的程序中定义的函数,即需要由用户自己编写的函数。

5 例 7.1 用户自定义函数——求数的平方。 #include <stdio.h> 
例 7.1 用户自定义函数——求数的平方。 #include <stdio.h>  long square(long); /* 函数声明 */ void main()  { long in-num, result;  printf("Input an integer: ");  scanf("%ld", &in-num);  result=square (in-num); /* 函数调用 */ printf("\nThe square number of %ld is %ld", in-num, result); }

6 long square (long x) /* 函数定义 */
{ long x-square; /* 说明部分 */ x-square=x*x; /* 执行部分 */  return x-square;  }  Input an integer: 100 (输入) The square number of 100 is (输出)

7 7.2 函数的定义和声明 7.2.1 函数的定义 例 7.2 计算x的n次方,x=2,-3;(n=1, 2, … 9)。
7.2 函数的定义和声明 7.2.1 函数的定义 例 计算x的n次方,x=2,-3;(n=1, 2, … 9)。 #include<stdio.h> int main(void) /* 测试power函数 */ { int i;  double power(int, int); /* 函数声明 */ for(i=1; i<10; i++) printf("power(2, %d)=%8.4f, power(-3, %d)=%11.4f\n",

8 i, power(2, i), i, power(-3, i));
return 0;  } double power(int x, int n) /* 函数首部 */ { int i; /* 说明部分 */ double p;  p=1; /* 执行部分 */ for(i=1; i<=n; i++) p*=x;  return(p); /* 返回p值 */ }

9 输出:  power(2, 1)= 2.0000, power(-3, 1)= -3.0000 power(2, 2)= 4.0000, power(-3, 2)= 9.0000 power(2, 3)= 8.0000, power(-3, 3)= -27.0000 power(2, 4)= 16.0000, power(-3, 4)= 81.0000 power(2, 5)= 32.0000, power(-3, 5)= -243.0000 power(2, 6)= 64.0000, power(-3, 6)= 729.0000 power(2, 7)=128.0000, power(-3, 7)= .0000power(2, 8)=256.0000, power(-3, 8)= .0000power(2, 9)=512.0000, power(-3, 9)=-19683.0000

10 函数名power是一个标识符,power函数具有double类型的返回值,它有两个int类型的参数x和n。{ }括起来的部分是函数体,其中的说明部分“int i; double p;” 说明i、p是在power函数内部使用的局部变量。执行部分的“return(p);”语句将表达式p的值返回给main函数的调用处,p的值就是power函数的返回值(简称函数值)。  函数定义的一般形式为:  存贮类型标识符 类型标识符 函数名(形式参数表列及类型说明) { 说明部分 语句部分

11 1) 存贮类型标识符 存贮类型标识符说明函数的存贮类型, 它规定了函数可被调用的范围。可用于函数的存贮类型标识符有static和extern,指定为static的函数为静态函数,静态函数局部于它所在的文件,即只能由和它在同一文件中定义的函数调用; 不指定存贮类型标识符时为缺省的存贮类型extern,缺省或指定为extern存贮类型的函数是外部函数,例如,例7.2中的power函数是外部函数。 外部函数可以被任何函数调用。

12 2) 类型标识符 C程序中定义的函数可以什么也不返回而只完成某项工作。无返回值的函数,类型标识符为void,又称为“空类型函数”,即此函数不向主调函数返回值,主调函数也禁止使用此函数的返回值。  C程序中定义的函数也可以返回一个值,这时,类型标识符说明函数返回值的数据类型(常简称为“函数值的类型”或“函数的类型”),例如,例7.2中的power函数是一个double类型函数,main是int类型函数。函数的类型可以为任何基本类型、结构体和共用体类型。还可以定义返回值为指针的函数,但不能定义返回数组的函数。int型函数定义时可以省略类型标识符int,因为int是有返回值函数的缺省类型(提倡明确指出int)。

13 3) 函数名 函数名是一个标识符,一个程序中除主函数main外,其余函数的名字可以任意取,最好取有助于记忆的名字。考虑到与外部联接的需要, 函数名一般不要超过6个字符长, 如max(),power( )和factor()等。外部函数的名字是作用于整个程序,因而外部函数相互之间不能同名。静态函数可以和外部函数同名,但同一文件中的函数不能同名。

14 4) 参数表 函数定义中的参数表说明函数参数的名称、类型和数目。 参数表由零个或多个参数说明组成,如果函数没有参数,可只写一对括号(此为函数标志,不可省略), 但最好将参数表指定为void。有多个参数时,多个参数之间用逗号隔开。 函数定义中的参数表习惯上称为形参表。  形参说明的一般形式为 类型标识符 形参名 每个类型标识符对应于一个形参名, 当有多个形参时, 相互间用逗号隔开。 

15 5) 函数体和函数返回值 函数定义中最外层{}括起来的部分称为函数体,函数体由说明部分和执行部分组成。说明部分是局部说明,执行部分是可执行语句的序列, 完成本函数要完成的具体任务。 局部说明中说明的变量和函数其有效范围局限于该函数内部, 同形参一样,不能由其它任何函数存取(或调用)。 函数体语法上是一个复合语句,它可以没有说明部分而只有执行部分,也可以两者都没有。因此最简单的合法函数是形参表为空(void)且函数体也为空的函数(称为哑函数), 例如: void dummy(void){ }

16 7.2.2 函数的声明 函数声明的一般形式:  存贮类型标识符 类型标识符 函数名(形参表); 
函数的声明 函数声明的一般形式:  存贮类型标识符 类型标识符 函数名(形参表);  外部函数声明时可指定extern或存贮类型标识符缺省, 静态函数声明时必须指定static;参数表可以只列出参数的类型名而不需给出参数名。例如:  double power(int, int);  和 double power(int x, int n);  是等价的。power函数是double类型,它有两个int参数。 对于无参数表的函数, 声明时参数表应指定为void。

17 7.3 函 数 的 调 用 7.3.1 函数调用的方式和条件 函数调用的一般形式为:  函数名(实参1, 实参2, …, 实参n) 
7.3 函 数 的 调 用 7.3.1 函数调用的方式和条件 函数调用的一般形式为:  函数名(实参1, 实参2, …, 实参n)  ( )部分称为实参表, 实参可以是常量、 变量或表达式, 有多个实参时, 相互间用逗号隔开。实参和形参应在数目、 次序和类型上一致。对于无参数的函数,调用时实参表为空,但( )不能省。

18 (1) getch( ); getch函数调用作为语句出现。 
(2) c=getchar();getchar函数调用作表达式出现(赋值表达式的右操作数)。 (3) while(putchar(getche())! =′?′);  getche函数调用作为putchar函数调用的实参(表达式)出现, putchar函数调用作为关系表达式的左操作数(表达式)出现。  (4) while((c=getch())! =′?′) putchar(c);  putchar函数调用作为while语句的循环体(语句)出现。

19 函数调用的一般过程为:  (1) 主调函数在执行过程中,一旦遇到函数调用,系统首先计算实参表达式的值并为每个形参分配存贮单元,然后把实参值复制到(送到或存入)对应形参的存贮单元中。实参与形参按位置一一对应。  (2) 将控制转移到被调用的函数,执行其函数体内的语句。 (3) 当执行return语句或到达函数体末尾时,控制返回到调用处,如果有返回值,同时回送一个值。然后从函数调用点继续执行主调函数后面的操作。

20 除了正确地编写函数的定义及调用语句, 要想成功地调用某个函数还必须满足下列四个条件之一: 
(1) 被调用函数的定义出现在主调函数的定义之前。 (2) 在主调函数中或主调函数之前的外部对被调用函数进行声明。  (3) 被调用函数的返回值为int型。  (4) 被调用函数为标准函数时, 在函数调用前已包含了相应的头文件。

21 7.3.2 形参与实参的数值传递 例 7.3 形参与实参的数值传递。 运行结果:  a=10 b=20
例 7.3 形参与实参的数值传递。 void swap(int x, int y) { int z;  z=x; x=y; y=z;  } main() { int a, b;  a=10; b=20;  swap(a, b);  printf("a=%d\tb=%d\n", a, b);  运行结果:  a=10 b=20

22 图 7.2

23 例 7.4 参数的求值顺序。 void main(void) { int x=0;  printf("x=%d\n", x); 
例 7.4 参数的求值顺序。 void main(void) { int x=0;  printf("x=%d\n", x);  printf("x++=%d x++=%d\n", x++, x++);  } 执行时输出:  x=0 x++=1 x++=0 x=2

24 7.3.3 函数的返回值 例 7.5 函数的返回值。 max(float x, float y)
函数的返回值 例 7.5 函数的返回值。 max(float x, float y) { if(x>=y) return(x);  else return(y);  } main() { float a, b, c;  scanf("%f%f", &a, &b);  c=max(a, b);  printf("max=%5.2f\n", c);  } 运行情况如下:  max= 5.00

25 7.4 函数的嵌套与递归 7.4.1 函数的嵌套调用 例 7.6 输入三个数,计算以它们作为两个底的半径和高所形成的圆台的体积。
7.4 函数的嵌套与递归 7.4.1 函数的嵌套调用 例 7.6 输入三个数,计算以它们作为两个底的半径和高所形成的圆台的体积。 分析:已知圆台的上下底的半径, 可用下式计算圆台的体积

26 程序如下: #include <stdio.h> #include <math.h>
#define PI  float area(float r) { return(PI*r*r);  } float volume(float r1, float r2, float h) { float v;  v=h*(area(r1)+area(r2)+sqrt(area(r1)*area(r2)))/3.0;  return(v); }

27 运行结果 Please input r1 r2 h:  2.5 6.8 3.3 The volume is 240.140762
main() { float r1, r2, h;  printf("Please input r1 r2 h:\n");  scanf("%f%f%f", &r1, &r2, &h);  printf("The volume is %f\n", volume(r1, r2, h));  } 运行结果 Please input r1 r2 h:  The volume is

28 7.4.2 函数的递归及条件 递归是一种特殊的解决问题的方法, 要用递归解决问题,应满足两个条件: 
函数的递归及条件 递归是一种特殊的解决问题的方法, 要用递归解决问题,应满足两个条件:  (1) 函数直接或间接地调用它本身;  (2) 应有使递归结束的条件。

29 例 7.7 用函数递归方法以字符串形式输出一个整数。
例 7.7 用函数递归方法以字符串形式输出一个整数。 #include<stdio.h> void printd(int n) { if(n<0)  {putchar(′-′);  n=-n;  } if(n/10) /* n/10==0时, 递归结束 */ printd(n/10); /* 递归调用 */ putchar(n%10+′0′); /* 以字符输出 */ void main() { int number;  scanf("%d", &number);  printd(number); 

30 7.5 变量的存贮类别 7.5.1 变量的作用域和生存期 例 7.8 变量的作用域。 #include <stdio.h>
7.5 变量的存贮类别 变量的作用域和生存期 例 7.8 变量的作用域。 #include <stdio.h> int x=999; /* 定义全局变量x */ void print-value(void);  void main() { printf("%d\n", x);  print-value();  } void print-value(void) 输出: 999 999

31 例 7.9 变量的作用域。 #include <stdio.h> void print-value(void); 
例 变量的作用域。 #include <stdio.h> void print-value(void);  void main() { int x=999; /* 定义局部变量x */ printf("%d\n", x);  print-value();  } void print-value(void)  { printf("%d\n", x);  }

32 动态存贮和静态存贮 内存中供用户使用的存贮空间可分为程序区、动态存贮区和静态存贮区。程序区用来存放程序代码,动态存贮区和静态存贮区用来存放数据,即数据与处理数据的程序是分离的,这是面向过程的程序设计方法的特点。  动态存贮和静态存贮是指C对数据存贮的两种方式。动态存贮是指存贮一些数据的存贮单元可在程序运行的不同时间分配给不同的数据,而静态存贮是指存贮单元在程序运行的整个过程中固定地分配给某些数据。

33 7.5.3 局部变量 局部变量又称内部变量,是在一个函数内定义,其作用域限制在所定义的函数中。 例 7.10 局部变量与全局变量同名。
例 局部变量与全局变量同名。 int a=1, b=2; /* 定义全局变量a、 b */ max(int a, int b) /* 子函数中的局部变量a、 b */ {int c;  c=a>b?a: b;  return(c);  } main() {int a=8; /* 定义局部变量a */ printf("%d", max(a, b));  运行结果:  8

34 7.5.4 局部静态变量的使用 例 7.11 静态局部变量的使用。 void f() { int a, b=3; 
例 静态局部变量的使用。 void f() { int a, b=3;  static int c, d=5;  a=3; c=5;  a++; b++; c++; d++;  printf("%d \t %d \t %d \t %d\n", a, b, c, d);  } main() { f(); f();  运行结果: 

35 例 打印1到5的阶乘。 fac(int n) { static int f=1;  f*=n;  return(f);  } main() { int i;  for(i=1; i<=5; i++) printf("%d!=%d\n", i, fac(i)); 

36 运行结果:  1! =1 2! =2 3! =6 4! =24 5! =120

37 全局变量 全局变量(也称外部变量)是在所有函数、包括main函数之外定义的。全局变量是存放在静态存贮区中的,它的作用域是从全局变量定义之后直到该源文件结束的所有函数;通过用extern作引用说明,全局变量的作用域可以扩大到整个程序的所有文件。在定义全局变量时可以使用static存贮类型标识符,它与普通全局变量的区别在于变量的作用域。普通全局变量不仅对文件中的所有函数都是可见的, 而且能被其它文件中的函数所用;而static型的全局变量仅对其所在文件中定义处之后的函数是可见的,不能被其它文件使用。这种差别适合于程序源代码包含在两个或多个文件中的情况。

38 全局变量初始化是在全局变量定义时进行的,且其初始化仅执行一次,若无显式初始化,则由系统自动初始化为与变量类型相同的0初值: 
整型变量初始化为整数0 浮点型变量初始化为浮点数0.0 字符型变量初始化为空字符′\0′ 在有显式初始化的情况下,初值必须是常量表达式。全局变量存放在静态存贮区中,全局变量在程序执行之前分配存贮单元, 在程序运行结束后才被收回。

39 例7.13 输入以秒为单位的一个时间值,将其转化成“时: 分:秒”的形式输出。将转换工作定义成函数。
例7.13 输入以秒为单位的一个时间值,将其转化成“时: 分:秒”的形式输出。将转换工作定义成函数。 #include<stdio.h> int hh, mm, ss;  void convertime(long seconds) { hh=seconds/3600;  mm=(seconds-hh*3600L)/60;  ss=seconds-hh*3600L-mm*60;  } void main(void) { long seconds;

40 input a time in second: 41574  (输入) 11: 32: 54 (输出)
printf("hh=%d, mm=%d, ss=%d\n", hh, mm, ss);  printf("input a time in second: ");  scanf("%ld", &seconds);  convertime(seconds);  printf("%2d: %2d: %2d\n", hh, mm, ss);  } 执行时输出:  hh=0, mm=0, ss=0 input a time in second:  (输入) 11: 32: (输出)

41 7.5.6 寄存器变量 例 7.14 计算 s=x1+x2+x3+…+xn,x和n由终端输入。
寄存器变量 例 计算 s=x1+x2+x3+…+xn,x和n由终端输入。 #include<stdio.h> long sum(register int x, int n) { long s;  int i;  register int t;  t=s=x;  for(i=2; i<=n; i++) {t*=x;  s+=t;  }

42 Input x, n: 4 5 S=1364 return(s);  } main() { int x, n; 
printf("Input x, n:");  scanf("%d %d", &x, &n);  printf("s=%ld\n", sum(x, n));  } 执行时输出:  Input x, n: 4 5 S=1364


Download ppt "第七章 函数及变量存贮类型 7.1 函数基础与C程序结构 7.2 函数的定义和声明 7.3 函数的调用 7.4 函数的嵌套与递归"

Similar presentations


Ads by Google