1 / 76

第一章 函数与宏定义

第一章 函数与宏定义. 1.1 函数概念. 1.2 变量作用域和存储类型. 1.3 内部函数与外部函数. 1.4 递归函数设计和调用. 1.5 预处理. 1.6 综合范例. 1.1 函数概念. 函数是 C 程序 的基本组成单位 , 每个 C 程序由一个主函数 main() 和任意个函数组成。 每个函数对应特定的功能。意义 :. ( 1 ) 便于设计复杂的大程序 。. ( 2 ) 便于程序的维护和扩充。. main ( ). a. b. c. . x. z. d.

Télécharger la présentation

第一章 函数与宏定义

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第一章 函数与宏定义 1.1 函数概念 1.2 变量作用域和存储类型 1.3 内部函数与外部函数 1.4 递归函数设计和调用 1.5 预处理 1.6 综合范例

  2. 1.1函数概念 函数是C程序的基本组成单位,每个C程序由一个主函数main()和任意个函数组成。每个函数对应特定的功能。意义: (1) 便于设计复杂的大程序。 (2) 便于程序的维护和扩充。

  3. main ( ) a b c  x z d C程序由一个main和任意个函数组成。 1)程序从main开始执行,最后又回到main函数结束。 2)由主函数调用其他函数,其他函数也可以互相调用,且同一函数可以被一个或多个函数调用任意次。 3) 除main外, 其它为标准库函数、用户自定义函数, 标准库函数:由系统提供,用户可调用。 用户自定义函数:由用户按语法规则编写。

  4. 库函数简介 系统自带的标准库函数根据不同的功能作用放在不同的头文件中。 stdio.h  用于标准输入/输出 math.h  用于数学计算 ctype.h  用于字符处理 string.h  用于字串处理 time.h  用于时间/日期的处理 graphics.h  用于图形操作  库函数的使用提高了编程效率。使用时只需在程序的开头加上一条语句: #include <.h> 根据使用的函数来确定

  5. 函数体 1.1.1 函数定义 [存储类型符] [返回值类型符] 函数名([形参说明表]) { 说明部分 执行部分 }

  6. 例 1: 定义函数hello,在屏幕上输出“Hello World!” hello () { printf(“Hello World!\n”); } 例 2: 定义函数add,实现整数的加法运算 add (int x, int y) { int result; result=x+y; printf(“%d”,result); } int add (int x, int y) { int result; result=x+y; return result; }

  7. 函数返回语句的形式有以下两种: 1、函数无返回值的情况 return;或 根本没有return语句 2、函数有返回值的情况 return (表达式); 或 return 表达式; 例 3: 定义函数max,找出两个整数中的最大值并返回 int max (int x, int y) { int m; m=x>y? x : y ; return m; }

  8. 1.1.2 函数声明和调用 一、 函数的声明 调用函数前应对被调用函数进行声明(说明),目的是告诉编译器所要使用的函数的信息,便于编译器对函数调用作精确的类型检查。 函数声明的一般形式: [存储类型符][返回值类型符] 函数名( [形参说明表]); 如: int max(int x,int y);

  9. 函数声明 例:求二实数之和(1-1.c)。 main ( ) { float add(float x, float y ); float a, b, c; scanf("%f, %f",&a, &b); c=add(a, b); printf ("sum= %f";c); } float add( float x, float y) { float z; z=x+y; return z; } 函数调用 函数定义 例1、例2 当函数定义在函数调用之前时,可省略对被调函数的声明。

  10. 二、 调用方式 (1)无返回值的情况     函数名([实参列表]); (2)有返回值的情况     变量名=函数名([实参列表]);

  11. 单向 实参值 形参。 传递 1.1.3 函数的传值方式 函数参数 实参: 出现在函数调用中的参数。 形参: 出现在函数定义中的参数。 临时分配单元给形参 调用时: 调用完毕,释放形参单元。

  12. 例:(1-2.c) int max (int x, int y) {int z; z=x>y? x:y; return (z); } main( ) {int a, b, c; scanf("%d, %d", &a, &b); c=max(a, b); printf("max=%d\n", c); }

  13. 例1-2.c函数调用中参数传递过程为: 在main函数中 int a, b, c; a 10 scanf("%d, %d", &a, &b); b 15 c 15 c=max(a, b); int max(int x, int y) { int z; x 10 z=x>y? x:y; y 15 15 z return(z); }

  14. 注意(函数参数): 形参变量在被调用前不占用存储单元;在调用结束后,形参所占存储单元亦被释放。  实参可以是常量、变量或表达式。  必须指定形参类型,且必须与实参的类型一致。  实参对形参的数据传递是“传值方式”。即单向传递,不能逆传。

  15. 例:阅读下列程序,写出运行结果(1-3.c) swap(int x, int y) {int t; a 15 t=x; x=y; y=t; b 19 printf("x=%d, y=%d\n", x, y);} main( ) { int a, b; scanf("%d, %d", &a, &b); x 15 19 y 15 if (a<b) swap(a, b); 19 15 t printf("a=%d, b=%d\n", a, b); }

  16. 关于main函数的参数: 一般情况下,main函数均无参数,但这并不表示main 函数必须为无参函数,在必要时,main函数也可以带有参数。

  17. 实参传递给形参时,实参的计算有的系统自左至右,有的自右至左。实参传递给形参时,实参的计算有的系统自左至右,有的自右至左。 例  int f(int a,int b) { int c; if(a>b) c=1; else if(a==b) c=0; else c=-1; return(c); } main() { int i=2,p; p=f(i,++i); printf("%d",p); } Turbo C是按自右至左的顺序求实参表的值,所以上机运运行结果为0。

  18. 注意(函数返回值): • 一个函数中可以有一个以上的return语句,执行到哪一个return语句,则哪一个语句起作用。 如:#include "stdio.h“ fun(int x, int n); main( ) { int n=4, x=2, s; s=fun(x, n); printf("s=%d\n", s); } fun(int x, int n) { if (n==1) return(x); else return(xfun(x, n1)); }

  19. 如果函数定义中没有给出函数值类型,一律按int型处理。如果函数定义中没有给出函数值类型,一律按int型处理。 如:float max(float x, float y) 函数值为float型 char letter(char c1, char c2) 函数值为字符型 f(int a, int b) 函数值为int型

  20. 当函数值类型与return语句中表达式类型不一致时,以函数值类型为准。对数值型数据,可以自动进行类型转换。即函数类型决定返回值的类型。1-2.c  int z->float z (这种方法初学者最好不用) • 若被调函数中没有return语句,将不带回一个确定的、用户希望的函数值。但实际上,并非不带回值,而只是不带回有用的值,带回的是一个不确定的值。

  21. 如:(1-4.c) printstar( ) {printf("************\n"); } print_message( ) {printf(" How do you do!\n");} main ( ) {int a, b, c; a=printstar( ); b=print_message( ); c=printstar( ); printf("a=%d, b=%d, c=%d\n", a, b, c); } }

  22. 为了明确表示不需要函数返回值,可以用“void”定义函数为“无类型”。此时,不得使用a=printstar( )之类的语句。 练习: • 编写计算圆面积的函数并调用(1-5.c)。 • 编写由三角形三条边求面积的函数并调用(1-5-0.c)。 • 打印出1000以内的所有素数,要求用到函数yes(n),其功能为判断某数n是否为素数(1-9.c)。 • 计算1+(1+2)+(1+2+3)+…+(1+2+3+…+n) 要求(1)n由键盘输入 (2)每项的计算由函数完成(1-10.c)。

  23. main {  调用a  } a( ) {  调用b  } b( ) { } 1.1.4 函数互相调用 主函数调用其他函数,其他函数也可以互相调用。 函数不能嵌套定义,但可嵌套调用

  24. 例:编写求组合数的函数。(1-6.c) 组合数的计算公式为: → 从程序中可以看到: (1)在定义函数时,函数fac、comb是互相独立的; (2)二个函数的定义均在主函数之前,所以在主函数中不必再对它们进行声明(说明);

  25. main函数 comb函数 fac函数 调用comb函数 调用fac函数 输出c (3)程序从主函数main()开始执行,首先执行的scanf( ),输入数,然后调用comb(n,m),调用comb的过程中,要调用fac( )。fac( )的调用是嵌套在函数comb( )的调用中进行的 ,其嵌套调用过程如下:

  26. 例1:任何一个整数n的立方都可以表示为n个相邻奇数之和。其中最大奇数为d=2m-1,而m=1+2+3+…+n。 (1-7-0.c) 算法: • 从键盘输入整数n; • 求m=1+2+3+…+n的值; • 求d=2m-1的值; • 求所有奇数d, d-2, d-4, …, d-2*(n-1)。 例2:定义函数max(a,b,c),功能为求三个整型数中的最大值。利用该函数,编程求五个数的最大数(1-7.c) 。

  27. 1.2变量作用域及存储类型 一、变量作用域    根据变量的有效作用范围,变量可分为局部变量和全局变量。 1、局部变量 凡在函数(含main 函数)内部定义的变量称为局部变量。 局部性: 局部变量仅在函数内部有效,它包括:

  28. 1. 函数中定义的变量; 不同的函数可具有同名的变量, 它们占不同的内存单元, 互不影响。 2. 形式参数; 3. 在复合语句中可定义仅复合语句中有效的临时变量。(1-11.c )

  29. 2、全局变量 一个源文件中,在所有函数之外定义的变量为全局变量。 有效性:自定义位置开始至文件结尾全部有效。

  30. 例: int p=1, q=5; float f1(int a) {int b, c;  } char c1, c2; p,q的作用范围 char f2(int x,int y); { int i, j;  } main ( ) }  } c1, c2的作用范围

  31. 1. 全局变量可以增强各函数间数据的联系。同一文件中的所有函数都能引用全局变量的值。当一个函数对其值进行改变后,另一个函数使用该变量的值亦相应改变。好处: 函数之间值传递。 2.不要随意使用全局变量。一是始终占据内存单元;二是由于函数依赖于外部定义的变量,降低了通用性。 3.不在全局变量作用域内的函数。若要使用全局(外)变量,需在函数体内加上extern保留字予以说明。 4.全局和局部变量同名时,局部变量有效。

  32. 例: float f1 (int x) {extern int a, b;  } int a=0; b= –1 main ( ) {  } a, b作用域

  33. int m=13; • int fun(int x, int y) • {int m=3; • printf("m1=%d\n",m); • return(x*y-m); } • main() • {int a=6,b=7; • printf("m2=%d\n",m); • printf("%d\n",fun(a,b)/m); } x, y m 全局变量m的作用范围 a, b 例:分析m作为全局变量和局部变量在程序中各个部分时的值。(1-12.c )

  34. 程序区 静态存储区 动态存储区 内存分配 数据,变量存放 二、 变量的存储类型 1、变量的存储类型 说明变量占用存储空间的区域。

  35. 静态存储变量: 存放于静态存储区,在程序整个运行过程中,始终占据固定的内存单元。 动态存储变量: 存放于动态存储区,根据程序的运行状态(如:函数调用)而临时分配的单元,且单元并不固定。

  36. 常用的变量存储类型有三种: 1.自动 (auto)型 2.静态(static)型 3.外部(extern)型

  37. 2、局部变量存储形式 局部变量既可以静态方式 , 又可以动态方式存储。 动态方式: auto int a, b; 则: a, b为自动型,存入动态区。在该函数被调用时才分配单元,函数调用结束时释放。 auto一般省略。以前用到的变量均为auto型, (除加static说明的之外)。 在变量初始化方面,auto型变量在每次函数调用时都赋一次初值。其默认初值不确定。 例:auto型变量的初始化 (1-13-0.c  )

  38. 静态方式: static int a, b; 则: a, b存入静态区。 函数中的a, b始终占据固定存储单元。 如果希望在函数调用结束后仍然保留函数中的局部变量的值,则可以把该变量定义为静态局部变量。 在变量初始化方面,静态局部变量是在第一次调用函数时赋初值的,且只赋一次初值。默认初值为0。 例:static局部变量的初始化 (1-13-0.c  ) 例:求n! (1-13.c )

  39. 2、全局变量存储形式 在函数外部中定义,它们一定存放在静态存贮区中。 全局变量既可被本文件中各函数用,亦可被其它源文件中的函数引用。 (1)只被本文件中的函数引用 全局变量本身一定是存放在静态区的。但若加上 static. 即:

  40. static int a, b; float f1(x) int { } 则表明a,b只被本文件中各函数引用,即使与其它文件中的全局变量同名,也互不影响。

  41. (2)可被其它文件中的函数引用(外部类型,默认)(2)可被其它文件中的函数引用(外部类型,默认) extern int a; fac(x) int x {  z=a  } int a; main( ) {  } 文件f2.c用到f1.c 中的a 文件f1.c f2.c中的extern在函数外说明,在函数内说明已叙述过。

  42. 函数内 函数外 存储类别 存在性 作用域 作用域 存在性 auto     static 局部     (只限本文件) static 全局    不加static 全局(外部)     总结 例:静态局部变量的作用域与存在性 (1-13-1.c )

  43. 1.3内部函数与外部函数 函数本身在一个文件中为全局的。即函数可被其所在文件的所有其它函数引用。 但函数能否被其它文件中的函数所引用呢? 为此分为: 内部函数、外部函数 一、内部函数–––只能在本文件中调用 static 类型标识符 函数名(形参表)

  44. 例: static int max (int a, int b) {  } 则该函数max只能被本文件中的其它函数引用,而不能被其它文件中的函数引用。即如果在不同的文件中有同名的内部函数,将互不干扰。

  45. 二、外部函数 既可被本文件中的函数调用,也可被其它文件中的函数调用。 extern 类型标识符 函数名(形参表) extern 可省略 一般系统在调用外部函数的函数中用extern说明外部函数。

  46. 例: (1-14.c 1-15.c ) /*file2.c*/ extern int add(int m, int n) { return (m+n); } /*file1.c*/ #include<stdio.h> int mod(int a, int b); extern int add(int m, int n); main() { int x,y,result; scanf(“%d%d”,&x,&y); result=add(x,y); if (result>0) result=result-mod(x,y); printf(“result=%d\n”,result); } int mod(int a,int b) { return (a%d); }

  47. 由多个源文件组成一个程序: 1. 命令方式。 2. 建立项目文件。 3. 使用文件包含命令。

  48. 首先要生成两个源文件(file1.c 和file2.c)。再构造project文件,在编辑状态下,编辑一个后缀为prj的文件(文件名可由用户选择,如:ff.prj)此文件内容如下: file1 file2 后缀.c可有可无,file1,file2顺序无关,如果是file1.c和file2.c不在一个目录中时,可在project文件ff.prj中给出各自的路径。 选择project功能项,在project name输入ff.prj。 然后按F9,产生相应的执行文件ff.exe 。

  49. 1.4 递归函数设计和调用 递归调用: 在函数内调用函数本身,称为函数的递归调用。函数直接调用本身,称为直接递归。函数调用其他函数 ,其他函数又调用了本函数,称为间接递归。

  50. 直接调用 int f(int x) { int y, z;  z=f (y);  } 间接调用 int f1 (int x) { int y, z;  z=f2 (y);  } int f2 (int t) { int a, b;  a=f1 (y);  } 以上仅给出了递归的概念.

More Related