资源预览内容
第1页 / 共124页
第2页 / 共124页
第3页 / 共124页
第4页 / 共124页
第5页 / 共124页
第6页 / 共124页
第7页 / 共124页
第8页 / 共124页
第9页 / 共124页
第10页 / 共124页
亲,该文档总共124页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
教学内容教学内容函数基础函数基础教学目标教学目标应知应知函数的定义与调用函数的定义与调用应会应会进行有参、无参函数的定义并进进行有参、无参函数的定义并进行调用行调用进行有返回值、无返回值函数的进行有返回值、无返回值函数的定义与调用定义与调用难点难点函数的定义和调用方法函数的定义和调用方法英文词汇英文词汇中文名中文名call调用调用return value返回值返回值function函数函数declare声明声明parameter参数参数static静态的静态的extern外部的外部的global全局的全局的local局部的局部的例例例例1 1:在屏幕上打印五行在屏幕上打印五行在屏幕上打印五行在屏幕上打印五行”*”*”号,每行分别是号,每行分别是号,每行分别是号,每行分别是5 5个,个,个,个,3030个,个,个,个,4040个,个,个,个,2828个,个,个,个,5050个。个。个。个。i=1 to 5i=1 to 5printf(“*”)printf(“*”)i=1 to 30i=1 to 30printf(“*”)printf(“*”)i=1 to 40i=1 to 40printf(“*”)printf(“*”)i=1 to 28i=1 to 28printf(“*”)printf(“*”)i=1 to 50i=1 to 50printf(“*”)printf(“*”)#include #include void main()void main() int i;int i;for(i=1;i=5;i+)for(i=1;i=5;i+)printf(*);printf(*);printf(n);printf(n);for(i=1;i=30;i+)for(i=1;i=30;i+)printf(*);printf(*);printf(n);printf(n);for(i=1;i=40;i+)for(i=1;i=40;i+)printf(*);printf(*);printf(n);printf(n);for(i=1;i=28;i+)for(i=1;i=28;i+)printf(*);printf(*);printf(n);printf(n);for(i=1;i=50;i+)for(i=1;i=50;i+)printf(*);printf(*);printf(n);printf(n); 函数函数函数函数完成某一特定特定功能的模块,是程序设计的基完成某一特定特定功能的模块,是程序设计的基完成某一特定特定功能的模块,是程序设计的基完成某一特定特定功能的模块,是程序设计的基本单位。本单位。本单位。本单位。 “ “一个程序应该是轻灵自由的,它的一个程序应该是轻灵自由的,它的一个程序应该是轻灵自由的,它的一个程序应该是轻灵自由的,它的子过程子过程子过程子过程就象串在一就象串在一就象串在一就象串在一根线上的珍珠。根线上的珍珠。根线上的珍珠。根线上的珍珠。” ” Geoffrey JamesGeoffrey James的的的的编程之道编程之道编程之道编程之道 一个一个一个一个C C程序可以由一个程序可以由一个程序可以由一个程序可以由一个主函数主函数主函数主函数和和和和若干个函数若干个函数若干个函数若干个函数构成。由主函构成。由主函构成。由主函构成。由主函数调用其他函数。其他函数也可以互相调用。同一个函数可数调用其他函数。其他函数也可以互相调用。同一个函数可数调用其他函数。其他函数也可以互相调用。同一个函数可数调用其他函数。其他函数也可以互相调用。同一个函数可以被一个或多个函数调用任意多次。以被一个或多个函数调用任意多次。以被一个或多个函数调用任意多次。以被一个或多个函数调用任意多次。,g gh hmainmaina ab bc cd di ie ee ef fh hg g 一个源程序文件由一个或多个函数组成。一一个源程序文件由一个或多个函数组成。一个源程序文件是一个编译单位,即以个源程序文件是一个编译单位,即以源程序为源程序为单位进行编译单位进行编译,而不是以函数为单位进行编译,而不是以函数为单位进行编译 C程序的执行程序的执行从从main开始开始,调用其他函数后,调用其他函数后流程返回到流程返回到main函数,在函数,在main函数中结束函数中结束整个整个程序的运行程序的运行 所有的函数都是平行的,即在所有的函数都是平行的,即在定义函数时是定义函数时是互相独立的。互相独立的。从用户使用的角度看,函数有两种:从用户使用的角度看,函数有两种:从用户使用的角度看,函数有两种:从用户使用的角度看,函数有两种: 标准函数(库函数)标准函数(库函数)标准函数(库函数)标准函数(库函数):这是由系统提供的,用户不必自:这是由系统提供的,用户不必自:这是由系统提供的,用户不必自:这是由系统提供的,用户不必自己定义这些函数,可以直接使用它们己定义这些函数,可以直接使用它们己定义这些函数,可以直接使用它们己定义这些函数,可以直接使用它们 用户自己定义的函数:用户自己定义的函数:用户自己定义的函数:用户自己定义的函数:用以解决用户的专门需要。用以解决用户的专门需要。用以解决用户的专门需要。用以解决用户的专门需要。从函数的形式看,函数有两种:从函数的形式看,函数有两种:从函数的形式看,函数有两种:从函数的形式看,函数有两种: 无参函数无参函数无参函数无参函数:在调用无参函数时,主调函数并不将数据传:在调用无参函数时,主调函数并不将数据传:在调用无参函数时,主调函数并不将数据传:在调用无参函数时,主调函数并不将数据传送给被调用函数,一般用来执行指定的一组操作。送给被调用函数,一般用来执行指定的一组操作。送给被调用函数,一般用来执行指定的一组操作。送给被调用函数,一般用来执行指定的一组操作。 有参函数:有参函数:有参函数:有参函数:在调用函数时,在主调函数和被调函数之间在调用函数时,在主调函数和被调函数之间在调用函数时,在主调函数和被调函数之间在调用函数时,在主调函数和被调函数之间有数据传递。有数据传递。有数据传递。有数据传递。根据的运算结果:函数可以分为两种:根据的运算结果:函数可以分为两种:根据的运算结果:函数可以分为两种:根据的运算结果:函数可以分为两种: 有返回值函数有返回值函数有返回值函数有返回值函数:此类函数调用执行完后将向调用者返回:此类函数调用执行完后将向调用者返回:此类函数调用执行完后将向调用者返回:此类函数调用执行完后将向调用者返回一直执行结果,称为函数返回值。由用户定义的这种要返一直执行结果,称为函数返回值。由用户定义的这种要返一直执行结果,称为函数返回值。由用户定义的这种要返一直执行结果,称为函数返回值。由用户定义的这种要返回函数值的函数,必须在函数定义和函数说明中明确返回回函数值的函数,必须在函数定义和函数说明中明确返回回函数值的函数,必须在函数定义和函数说明中明确返回回函数值的函数,必须在函数定义和函数说明中明确返回值的类型。值的类型。值的类型。值的类型。 无返回值函数:无返回值函数:无返回值函数:无返回值函数:此类函数用于完成某项特定的处理任务,此类函数用于完成某项特定的处理任务,此类函数用于完成某项特定的处理任务,此类函数用于完成某项特定的处理任务,执行完成后不向调用者返回函数值。由于函数无须返回值,执行完成后不向调用者返回函数值。由于函数无须返回值,执行完成后不向调用者返回函数值。由于函数无须返回值,执行完成后不向调用者返回函数值。由于函数无须返回值,用户在定义此类函数时可指定它的返回值为用户在定义此类函数时可指定它的返回值为用户在定义此类函数时可指定它的返回值为用户在定义此类函数时可指定它的返回值为“ “空类型空类型空类型空类型” ”或或或或者者者者voidvoid。对于用户自定函数,必须满足函数三要素:对于用户自定函数,必须满足函数三要素:对于用户自定函数,必须满足函数三要素:对于用户自定函数,必须满足函数三要素: 函数声明函数声明函数声明函数声明 函数定义函数定义函数定义函数定义 函数调用函数调用函数调用函数调用函数类型函数类型 函数名函数名()声明部分声明部分语句语句函数函数函数函数首部首部首部首部函数体函数体函数体函数体函数体是用一对花括号括起来的语句函数体是用一对花括号括起来的语句函数体是用一对花括号括起来的语句函数体是用一对花括号括起来的语句系列,它描述了函数实现某一功能的系列,它描述了函数实现某一功能的系列,它描述了函数实现某一功能的系列,它描述了函数实现某一功能的执行过程。如果函数类型不为执行过程。如果函数类型不为执行过程。如果函数类型不为执行过程。如果函数类型不为voidvoid,则函数最后要执行返回。(则函数最后要执行返回。(则函数最后要执行返回。(则函数最后要执行返回。(returnreturn)详)详)详)详见课本见课本见课本见课本p95p95#include #include void main()void main() void printstar(); void printstar(); /对对对对printstarprintstar函数进行声明函数进行声明函数进行声明函数进行声明void print_message(); void print_message(); /对对对对print_messgeprint_messge函数函数函数函数进行声明进行声明进行声明进行声明printstar();printstar(); /调用调用调用调用printstarprintstar函数函数函数函数print_message();print_message(); /调用调用调用调用print_messgeprint_messge函数函数函数函数printstar();printstar(); /调用调用调用调用printstarprintstar函数函数函数函数 void printstar() void printstar() /定义定义定义定义printstarprintstar函数函数函数函数 printf(*n); printf(*n);void print_message() void print_message() /定义定义定义定义print_messageprint_message函数函数函数函数 printf( printf( 计算机科学与技术学院计算机科学与技术学院计算机科学与技术学院计算机科学与技术学院1010计计计计7272班班班班n); n); 设计函数的三位置:设计函数的三位置:设计函数的三位置:设计函数的三位置:函数声明函数声明函数声明函数声明、函数定义函数定义函数定义函数定义、函数调用函数调用函数调用函数调用函数类型函数类型函数类型函数类型 函数名函数名函数名函数名( (形式参数表列形式参数表列形式参数表列形式参数表列) ) 声明部分声明部分声明部分声明部分语句部分语句部分语句部分语句部分 形参列表形参列表形式:形式:类型名类型名形参形参1,类型名,类型名形参形参2,int max(int max(int x,int yint x,int y) ) int z;int z;z=xy?x:y;z=xy?x:y;return z;return z; 函数首部函数首部函数首部函数首部函函函函数数数数体体体体1 1、字符串函数、字符串函数、字符串函数、字符串函数strcat(),strcpy().strcmp(), strlenstrcat(),strcpy().strcmp(), strlen() ()注意:注意:注意:注意:(1 1)需要加头文件)需要加头文件)需要加头文件)需要加头文件string.hstring.h(2 2)这几个字符串函数的参数是字符数组名)这几个字符串函数的参数是字符数组名)这几个字符串函数的参数是字符数组名)这几个字符串函数的参数是字符数组名 (3 3)strlenstrlen() ()与与与与sizeof()sizeof()的区别的区别的区别的区别 (4 4)00的意义的意义的意义的意义及用法及用法及用法及用法 (5 5)不使用字符串函数实现)不使用字符串函数实现)不使用字符串函数实现)不使用字符串函数实现相应的功能相应的功能相应的功能相应的功能2 2、函数的意义、函数三要素、函数的意义、函数三要素、函数的意义、函数三要素、函数的意义、函数三要素3 3、函数的分类(从三个不同的方面)、函数的分类(从三个不同的方面)、函数的分类(从三个不同的方面)、函数的分类(从三个不同的方面)有参函有参函有参函有参函数与无参函数,有返回值的函数与无返回值的函数数与无参函数,有返回值的函数与无返回值的函数数与无参函数,有返回值的函数与无返回值的函数数与无参函数,有返回值的函数与无返回值的函数例例例例1 1:在屏幕上打印五行在屏幕上打印五行在屏幕上打印五行在屏幕上打印五行”*”*”号,每行分别是号,每行分别是号,每行分别是号,每行分别是5 5个,个,个,个,3030个,个,个,个,4040个,个,个,个,2828个,个,个,个,5050个。个。个。个。i=1 to ni=1 to nprintf(“*”)printf(“*”)print(5);print(5);print(30);print(30);print(40);print(40);print(28);print(28);print(50);print(50);#include #include void main()void main() void print(int n);void print(int n);print(5);print(5);print(30);print(30); print(40);print(40);print(28);print(28); print(50);print(50); void print(int n)void print(int n) int i;int i;for(i=1;i=n;i+)for(i=1;i=n;i+)printf(*);printf(*);printf(n);printf(n); 函数定义函数定义函数定义函数定义函数声明函数声明函数声明函数声明函数调用函数调用函数调用函数调用函数类型函数类型函数名函数名() 调用空函数时,什么工作也不做,没有实调用空函数时,什么工作也不做,没有实调用空函数时,什么工作也不做,没有实调用空函数时,什么工作也不做,没有实际作用际作用际作用际作用 在主函数中写上空函数,表明这里要调用在主函数中写上空函数,表明这里要调用在主函数中写上空函数,表明这里要调用在主函数中写上空函数,表明这里要调用一个函数,而现在这个函数没有起作用,等一个函数,而现在这个函数没有起作用,等一个函数,而现在这个函数没有起作用,等一个函数,而现在这个函数没有起作用,等以后扩充函数功能时补充上。以后扩充函数功能时补充上。以后扩充函数功能时补充上。以后扩充函数功能时补充上。 程序的结构清楚,可读性号,以后扩充新程序的结构清楚,可读性号,以后扩充新程序的结构清楚,可读性号,以后扩充新程序的结构清楚,可读性号,以后扩充新功能,对程序结构影响不大功能,对程序结构影响不大功能,对程序结构影响不大功能,对程序结构影响不大void void dummy() dummy() void dummy() void dummy() ; ; 函数声明函数声明函数声明函数声明 函数定义函数定义函数定义函数定义 函数调用函数调用函数调用函数调用 “ “声明声明声明声明” ”(declaration)(declaration)作用是把作用是把作用是把作用是把函数名函数名函数名函数名、函数参数的个数函数参数的个数函数参数的个数函数参数的个数和和和和参数的类型参数的类型参数的类型参数的类型等信息通知编译等信息通知编译等信息通知编译等信息通知编译系统,以便在遇到函数调用时,编译系统能够系统,以便在遇到函数调用时,编译系统能够系统,以便在遇到函数调用时,编译系统能够系统,以便在遇到函数调用时,编译系统能够正确识别并检查调用是否合法。正确识别并检查调用是否合法。正确识别并检查调用是否合法。正确识别并检查调用是否合法。void print(int n);void print(int n); 在函数声明中也可以不写形参名,而只写形在函数声明中也可以不写形参名,而只写形在函数声明中也可以不写形参名,而只写形在函数声明中也可以不写形参名,而只写形参的类型。参的类型。参的类型。参的类型。 编译系统只检查参数个数和参数类型,而不编译系统只检查参数个数和参数类型,而不编译系统只检查参数个数和参数类型,而不编译系统只检查参数个数和参数类型,而不检查参数名。检查参数名。检查参数名。检查参数名。 函数声明函数声明函数声明函数声明函数原型函数原型函数原型函数原型(function (function prototype)prototype)函数声明函数声明函数声明函数声明 函数定义函数定义函数定义函数定义 函数调用函数调用函数调用函数调用 “ “定义定义定义定义” ”( (definationdefination)是指对函数功能的确立,包是指对函数功能的确立,包是指对函数功能的确立,包是指对函数功能的确立,包括指定括指定括指定括指定函数名函数名函数名函数名、函数值类型函数值类型函数值类型函数值类型、形参名称形参名称形参名称形参名称及其及其及其及其类型类型类型类型、函数体函数体函数体函数体等。等。等。等。 它是一个完整的、独立的函数单位。它是一个完整的、独立的函数单位。它是一个完整的、独立的函数单位。它是一个完整的、独立的函数单位。void print(int n)void print(int n) int i;int i;for(i=1;i=n;i+)for(i=1;i=n;i+)printf(*);printf(*);printf(n);printf(n); 形参名不形参名不形参名不形参名不能省略能省略能省略能省略 函数定义与函数声明的区别函数定义与函数声明的区别函数定义与函数声明的区别函数定义与函数声明的区别 如果被调用函数的定义出现在主调函数之前,可以不必如果被调用函数的定义出现在主调函数之前,可以不必如果被调用函数的定义出现在主调函数之前,可以不必如果被调用函数的定义出现在主调函数之前,可以不必加以声明。加以声明。加以声明。加以声明。 如果已在文件的开头(在所有文件之前),已对本文件如果已在文件的开头(在所有文件之前),已对本文件如果已在文件的开头(在所有文件之前),已对本文件如果已在文件的开头(在所有文件之前),已对本文件所调用的函数进行了声明,则在各函数不必对其所调用的所调用的函数进行了声明,则在各函数不必对其所调用的所调用的函数进行了声明,则在各函数不必对其所调用的所调用的函数进行了声明,则在各函数不必对其所调用的函数再作声明函数再作声明函数再作声明函数再作声明函数声明函数声明函数声明函数声明 函数定义函数定义函数定义函数定义 函数调用函数调用函数调用函数调用 “ “调用调用调用调用” ”(Call)(Call)是指在主调函数中调用被调函数的过是指在主调函数中调用被调函数的过是指在主调函数中调用被调函数的过是指在主调函数中调用被调函数的过程程程程 函数名函数名函数名函数名( (实参列表实参列表实参列表实参列表);); 如果被调用的是无参函数,则如果被调用的是无参函数,则如果被调用的是无参函数,则如果被调用的是无参函数,则“ “实参表列实参表列实参表列实参表列” ”可可可可以没有,但是括号不能省略。以没有,但是括号不能省略。以没有,但是括号不能省略。以没有,但是括号不能省略。 如果实参表列包含多个实参,则各参数之间用如果实参表列包含多个实参,则各参数之间用如果实参表列包含多个实参,则各参数之间用如果实参表列包含多个实参,则各参数之间用逗号隔开逗号隔开逗号隔开逗号隔开 实参与形参的个数应相等,类型应匹配,实参与形参的个数应相等,类型应匹配,实参与形参的个数应相等,类型应匹配,实参与形参的个数应相等,类型应匹配, 实参与形参按照顺对应,一一传递数据实参与形参按照顺对应,一一传递数据实参与形参按照顺对应,一一传递数据实参与形参按照顺对应,一一传递数据 首先被调用的函数必须是已经存在的函数(是库函数首先被调用的函数必须是已经存在的函数(是库函数首先被调用的函数必须是已经存在的函数(是库函数首先被调用的函数必须是已经存在的函数(是库函数或用户自己定义的函数)或用户自己定义的函数)或用户自己定义的函数)或用户自己定义的函数) 如果使用库函数,还应该在本文件开头用如果使用库函数,还应该在本文件开头用如果使用库函数,还应该在本文件开头用如果使用库函数,还应该在本文件开头用” ”#include”#include”命令将调用有关库函数时所需用到的信息命令将调用有关库函数时所需用到的信息命令将调用有关库函数时所需用到的信息命令将调用有关库函数时所需用到的信息“ “包含包含包含包含” ”到本文件中来。到本文件中来。到本文件中来。到本文件中来。 如果使用用户自己定义的函数,而该函数的位置在调如果使用用户自己定义的函数,而该函数的位置在调如果使用用户自己定义的函数,而该函数的位置在调如果使用用户自己定义的函数,而该函数的位置在调用它的函数的后面,应该在主调函数中对被调函数作声用它的函数的后面,应该在主调函数中对被调函数作声用它的函数的后面,应该在主调函数中对被调函数作声用它的函数的后面,应该在主调函数中对被调函数作声明。明。明。明。函数的参数分为函数的参数分为形参形参和和实参实参两种两种U形参形参(形式参数形式参数):在在函数定义时函数定义时函数函数名后面括弧中的若干变量名后面括弧中的若干变量U实参实参(实在参数实在参数):在在调用函数时调用函数时,函,函数名后面括弧中的若干变量或表达式。数名后面括弧中的若干变量或表达式。形参与实参的功形参与实参的功能是完成数据的能是完成数据的传递传递例例例例22调用函数时的数据传递调用函数时的数据传递调用函数时的数据传递调用函数时的数据传递#include #include void main()void main() int max(int a,int b);int max(int a,int b); int x,y,z; int x,y,z; printf(input two numbers:n); printf(input two numbers:n); scanf(%d%d,&x,&y); scanf(%d%d,&x,&y); z=max(x,y);z=max(x,y); printf(maxmum=%dn,z); printf(maxmum=%dn,z); int max(int a,int b)int max(int a,int b) return(ab?a:b); return(ab?a:b); 函数声明函数声明函数声明函数声明函数调用函数调用函数调用函数调用函数定义函数定义函数定义函数定义 z=max(x,y); (main函数函数)int max(int a,int b)(max函数函数) return(ab?a:b); 例例例例33查找查找查找查找3 3个数里面的最大值个数里面的最大值个数里面的最大值个数里面的最大值#include #include void main()void main() int max(int a,int b);int max(int a,int b); int a,b,c,z; int a,b,c,z; printf(input three numbers:n); printf(input three numbers:n); scanf(%d%d%d,&a,&b,&c); scanf(%d%d%d,&a,&b,&c); z=max(a,b); z=max(z,c);z=max(a,b); z=max(z,c); printf(maxmum=%dn,z); printf(maxmum=%dn,z); int max(int a,int b)int max(int a,int b) return(ab?a:b); return(ab?a:b); 一个函一个函一个函一个函数可以数可以数可以数可以多次调多次调多次调多次调用用用用改写函数,一次性改写函数,一次性改写函数,一次性改写函数,一次性的输出三个数中的的输出三个数中的的输出三个数中的的输出三个数中的最大值最大值最大值最大值O 实参可以是常量、变量或者表达式。但是实参可以是常量、变量或者表达式。但是实参可以是常量、变量或者表达式。但是实参可以是常量、变量或者表达式。但是要求它们有要求它们有要求它们有要求它们有确定的值确定的值确定的值确定的值。在调用的时候将实参。在调用的时候将实参。在调用的时候将实参。在调用的时候将实参的值赋给形参。的值赋给形参。的值赋给形参。的值赋给形参。O 在函数声明和函数定义时,在函数声明和函数定义时,在函数声明和函数定义时,在函数声明和函数定义时,必须指定形参必须指定形参必须指定形参必须指定形参的类型的类型的类型的类型O 实参与形参的实参与形参的实参与形参的实参与形参的个数应相等,类型应匹配个数应相等,类型应匹配个数应相等,类型应匹配个数应相等,类型应匹配。O 实参与形参按顺序对应,一一传递数据。实参与形参按顺序对应,一一传递数据。实参与形参按顺序对应,一一传递数据。实参与形参按顺序对应,一一传递数据。函数的值:函数的值:函数的值:函数的值:指函数被调用之后,执行函数体中的程序段指函数被调用之后,执行函数体中的程序段指函数被调用之后,执行函数体中的程序段指函数被调用之后,执行函数体中的程序段所取得的并返回给主调函数的值。所取得的并返回给主调函数的值。所取得的并返回给主调函数的值。所取得的并返回给主调函数的值。例如,例如,例如,例如,调用调用调用调用max(x,y)max(x,y)得到得到得到得到x x与与与与y y中较大数中较大数中较大数中较大数说明:说明:说明:说明:(1 1)函数的值只能通过)函数的值只能通过)函数的值只能通过)函数的值只能通过returnreturn语句返回主调函语句返回主调函语句返回主调函语句返回主调函数。数。数。数。returnreturn语句的一般形式为:语句的一般形式为:语句的一般形式为:语句的一般形式为: return return 表达式;表达式;表达式;表达式; 或者为:或者为:或者为:或者为: return (return (表达式表达式表达式表达式) ); 注意:每次调用只能有一个注意:每次调用只能有一个注意:每次调用只能有一个注意:每次调用只能有一个return return 语句被执行,语句被执行,语句被执行,语句被执行,因此只返回一个函数值。因此只返回一个函数值。因此只返回一个函数值。因此只返回一个函数值。int max(int a,int b)int max(int a,int b) if(ab) if(ab)return a;return a;elseelsereturn b;return b; (2 2) 在在在在定义定义函数时指定函数值的类型。函数时指定函数值的类型。函数时指定函数值的类型。函数时指定函数值的类型。函数的值:函数的值:函数的值:函数的值:指函数被调用之后,执行函数体中的程序段指函数被调用之后,执行函数体中的程序段指函数被调用之后,执行函数体中的程序段指函数被调用之后,执行函数体中的程序段所取得的并返回给主调函数的值。所取得的并返回给主调函数的值。所取得的并返回给主调函数的值。所取得的并返回给主调函数的值。例如,调用例如,调用例如,调用例如,调用sin(x)sin(x)便得到便得到便得到便得到x x的正弦值的正弦值的正弦值的正弦值调用调用调用调用max(x,y)max(x,y)得到得到得到得到x x与与与与y y中较大数中较大数中较大数中较大数如:如:如:如: intint max(int x,int y) max(int x,int y) charchar letter(char c1,char c2) letter(char c1,char c2)(3 3)函数值的类型和函数定义中函数的类型应保持一)函数值的类型和函数定义中函数的类型应保持一)函数值的类型和函数定义中函数的类型应保持一)函数值的类型和函数定义中函数的类型应保持一致。致。致。致。如果两者不一致,则以如果两者不一致,则以如果两者不一致,则以如果两者不一致,则以函数类型函数类型为准,自动进行为准,自动进行为准,自动进行为准,自动进行类型转换。类型转换。类型转换。类型转换。函数的值:函数的值:函数的值:函数的值:指函数被调用之后,执行函数体中的程序段指函数被调用之后,执行函数体中的程序段指函数被调用之后,执行函数体中的程序段指函数被调用之后,执行函数体中的程序段所取得的并返回给主调函数的值。所取得的并返回给主调函数的值。所取得的并返回给主调函数的值。所取得的并返回给主调函数的值。例如,调用例如,调用例如,调用例如,调用sin(x)sin(x)便得到便得到便得到便得到x x的正弦值的正弦值的正弦值的正弦值调用调用调用调用max(x,y)max(x,y)得到得到得到得到x x与与与与y y中较大数中较大数中较大数中较大数floatfloat max(int x,int y)max(int x,int y) intint z; z; z=xy?x:y; z=xy?x:y; return z; return z; (4)不返回函数值的函数,可以明确定义为)不返回函数值的函数,可以明确定义为“空类型空类型”,类型说明符为,类型说明符为“void”#include #include void main()void main() void printstar(); void printstar(); /对对对对printstarprintstar函数进行声明函数进行声明函数进行声明函数进行声明void print_message(); void print_message(); /对对对对print_messgeprint_messge函数进行声函数进行声函数进行声函数进行声明明明明printstar(); printstar(); /调用调用调用调用printstarprintstar函数函数函数函数print_message(); print_message(); /调用调用调用调用print_messgeprint_messge函数函数函数函数printstar(); printstar(); /调用调用调用调用printstarprintstar函数函数函数函数 void printstar() void printstar() /定义定义定义定义printstarprintstar函数函数函数函数 printf(*n); printf(*n);void print_message() void print_message() /定义定义定义定义print_messageprint_message函数函数函数函数 printf( printf( 计算机科学与技术学院计算机科学与技术学院计算机科学与技术学院计算机科学与技术学院0707计计计计1111班班班班n); n); printstar(3)printstar(3)int z=printstar()int z=printstar()N 无参函数的声明、定义和调用时忘记加括号无参函数的声明、定义和调用时忘记加括号无参函数的声明、定义和调用时忘记加括号无参函数的声明、定义和调用时忘记加括号N 不应该在函数定义后面加分号不应该在函数定义后面加分号不应该在函数定义后面加分号不应该在函数定义后面加分号N 对无返回值的函数调用使用赋值语句对无返回值的函数调用使用赋值语句对无返回值的函数调用使用赋值语句对无返回值的函数调用使用赋值语句N 函数定义时的形参列表没有添加参数类型函数定义时的形参列表没有添加参数类型函数定义时的形参列表没有添加参数类型函数定义时的形参列表没有添加参数类型N 为什么使用函数,函数如何定义为什么使用函数,函数如何定义为什么使用函数,函数如何定义为什么使用函数,函数如何定义N 函数的参数起什么作用函数的参数起什么作用函数的参数起什么作用函数的参数起什么作用N 什么情况下使用用户函数比较好什么情况下使用用户函数比较好什么情况下使用用户函数比较好什么情况下使用用户函数比较好N 调用一个函数应该具备什么条件调用一个函数应该具备什么条件调用一个函数应该具备什么条件调用一个函数应该具备什么条件N 函数定义、函数调用、函数声明之间的关系函数定义、函数调用、函数声明之间的关系函数定义、函数调用、函数声明之间的关系函数定义、函数调用、函数声明之间的关系N 函数定义时函数类型同函数返回值有什么关系函数定义时函数类型同函数返回值有什么关系函数定义时函数类型同函数返回值有什么关系函数定义时函数类型同函数返回值有什么关系N 有返回值的函数和无返回值的函数分别如何调有返回值的函数和无返回值的函数分别如何调有返回值的函数和无返回值的函数分别如何调有返回值的函数和无返回值的函数分别如何调用,函数返回值是什么意思,有什么作用?用,函数返回值是什么意思,有什么作用?用,函数返回值是什么意思,有什么作用?用,函数返回值是什么意思,有什么作用?教学内容教学内容函数基础函数基础教学目标教学目标应知应知函数的定义与调用函数的定义与调用应会应会进行有参、无参函数的定义并进进行有参、无参函数的定义并进行调用行调用进行有返回值、无返回值函数的进行有返回值、无返回值函数的定义与调用定义与调用难点难点函数的定义和调用方法函数的定义和调用方法#include #include void main()void main() int max(int a,int b);int max(int a,int b); int a,b,z; int a,b,z; printf(input two numbers:n); printf(input two numbers:n); scanf(%d%d,&a,&b); scanf(%d%d,&a,&b); z=max(a,b);z=max(a,b); printf(maxmum=%dn,z); printf(maxmum=%dn,z); int max(int x,int y)int max(int x,int y) return(xy?x:y); return(xy?x:y); 例例例例4 4 对上节课对上节课对上节课对上节课maxmax函数的改进函数的改进函数的改进函数的改进对两个对两个对两个对两个形参形参形参形参分别加分别加分别加分别加2 2,再,再,再,再分别打印形参和实参分别打印形参和实参分别打印形参和实参分别打印形参和实参printf(a=%d,b=%dn,a,b);printf(a=%d,b=%dn,a,b);x=x+2;x=x+2;y=y+2;y=y+2;printf(x=%d,y=%dn,x,y);printf(x=%d,y=%dn,x,y);对两个实参加对两个实参加对两个实参加对两个实参加2 2?教学内容教学内容函数的参数传递方式函数的参数传递方式/函数的嵌套调用函数的嵌套调用/递归调用递归调用教学目标教学目标应知应知了解函数的两种传递方式:值传递和地址传递了解函数的两种传递方式:值传递和地址传递什么是嵌套调用,什么是递归调用什么是嵌套调用,什么是递归调用应会应会了解嵌套调用与递归调用时程序的执行顺序了解嵌套调用与递归调用时程序的执行顺序编写简单递归函数编写简单递归函数能够进行普通变量和数组元素做函数参数的程序能够进行普通变量和数组元素做函数参数的程序设计设计能够以数组名字作函数参数进行程序设计能够以数组名字作函数参数进行程序设计难点难点函数的两种传递方式函数的两种传递方式J函数调用中发生的数据传送是函数调用中发生的数据传送是“值传递值传递”,即单向传递,即单向传递。即只能把实参的值传送给形即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。因参,而不能把形参的值反向地传送给实参。因此在函数调用过程中,形参的值发生改变,而此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。实参中的值不会变化。J形参变量只有在被调用时才分配内存单元,形参变量只有在被调用时才分配内存单元,在调用结束时立即释放所分配的内存单元在调用结束时立即释放所分配的内存单元。因因此形参只有在函数内部有效。函数调用结束返此形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变量。回主调函数后则不能再使用该形参变量。1 1、使用全局变量使用全局变量使用全局变量使用全局变量2 2、使用指针使用指针使用指针使用指针3 3、在被调函数中在被调函数中在被调函数中在被调函数中输出结果输出结果输出结果输出结果例例例例5 5 对两个整数进行从大到小排序对两个整数进行从大到小排序对两个整数进行从大到小排序对两个整数进行从大到小排序#include #include void main()void main() void s);void s);int a,b;int a,b;printf(Please input two number:);printf(Please input two number:);scanf(%d%d,&a,&b);scanf(%d%d,&a,&b);s);s);printf(printf(交换后交换后交换后交换后:na=%d,b=%dn,a,b);:na=%d,b=%dn,a,b); void s x,int y)void s x,int y) int temp;int temp;temp=x;temp=x;x=y;x=y; y=temp; y=temp; 数组元素就是下标变量,它与普通变量并数组元素就是下标变量,它与普通变量并无区别。无区别。因此它作为函数实参使用与普通因此它作为函数实参使用与普通变量是完全相同的,在发生函数调用时,变量是完全相同的,在发生函数调用时,把作为实参的数组元素的值传送给形参,把作为实参的数组元素的值传送给形参,实现实现单向的值传送单向的值传送。值传递的特点:值传递的特点:值传递的特点:值传递的特点:1 1、实参和形参之间的传递数据是实参和形参之间的传递数据是实参和形参之间的传递数据是实参和形参之间的传递数据是值传递值传递值传递值传递单向行为单向行为单向行为单向行为;2 2、实参和形参都实参和形参都实参和形参都实参和形参都分别占有内存空间分别占有内存空间分别占有内存空间分别占有内存空间,大量的,大量的,大量的,大量的参数传递肯定占用系统较多的时间,降低系参数传递肯定占用系统较多的时间,降低系参数传递肯定占用系统较多的时间,降低系参数传递肯定占用系统较多的时间,降低系统效率。统效率。统效率。统效率。可以用可以用可以用可以用传递传递传递传递地址地址地址地址解决解决解决解决数组首地数组首地数组首地数组首地址址址址或者是或者是或者是或者是变量地址变量地址变量地址变量地址例例例例8 8 对例对例对例对例6 6改进,定义一个整型数组改进,定义一个整型数组改进,定义一个整型数组改进,定义一个整型数组a10a10,要求在,要求在,要求在,要求在一个函数中以一个函数中以一个函数中以一个函数中以数组首地址作实参数组首地址作实参数组首地址作实参数组首地址作实参将将将将a a数组中各个元素数组中各个元素数组中各个元素数组中各个元素的值加的值加的值加的值加2 2。int a10;int a10;给数组给数组给数组给数组a a赋初值赋初值赋初值赋初值add2(ai)add2(ai)i=0 to 9i=0 to 9outputoutput数组数组数组数组a aadd2(a)add2(a)add2(int n10)add2(int n10)i=0 to 9i=0 to 9ni+=2;ni+=2;函数类型?函数类型?函数类型?函数类型?#include #include void main()void main() int add2(int);int add2(int);int a10,i;int a10,i;printf(Please input array a:n);printf(Please input array a:n);for(i=0;i10;i+)for(i=0;i10;i+) printf(a%d=,i);printf(a%d=,i); scanf(%d,&ai); scanf(%d,&ai); for(i=0;i10;i+)for(i=0;i10;i+)ai=add2(ai);ai=add2(ai);printf(printf(加加加加2 2以后的数组为以后的数组为以后的数组为以后的数组为:n);:n);for(i=0;i10;i+)for(i=0;i10;i+)printf(%-3d,ai);printf(%-3d,ai);printf(n);printf(n); int add2(int n) int add2(int n) return n+2; return n+2; void add2(int);void add2(int);add2(a);add2(a);void add2(int n10)void add2(int n10) int i;int i;for(i=0;i10;i+) ni+=2;for(i=0;i10;i+) ni+=2; 实参数组单元实参数组单元函数调用时函数调用时形参数组单元形参数组单元:传传递递地地址址函数运行过程中函数运行过程中数组名作为函数参数时数组名作为函数参数时“按址传送按址传送”,这其实,这其实就实现了值的传递,而就实现了值的传递,而且这种值的传递是一种且这种值的传递是一种双向效果双向效果,即,即,当在被当在被调用函数中改变了数组调用函数中改变了数组元素的值,那么这种改元素的值,那么这种改变就是对实参数组的改变就是对实参数组的改变,这样的改变会在被变,这样的改变会在被调用函数结束后带回到调用函数结束后带回到调用函数中。调用函数中。例例例例9 9 有一个一维数组有一个一维数组有一个一维数组有一个一维数组scorescore,内放,内放,内放,内放1010个学生成绩,求平均成绩个学生成绩,求平均成绩个学生成绩,求平均成绩个学生成绩,求平均成绩float score10,avg;float score10,avg;给数组给数组给数组给数组scorescore赋初值赋初值赋初值赋初值avg=average(score);avg=average(score);output avg;output avg;i=0 to 9i=0 to 9sum+=arrayi;sum+=arrayi;return sum/10;return sum/10;average(float array10)average(float array10)函数类型?函数类型?函数类型?函数类型?float average(float average(float array10float array10) ) int i;int i;float aver,sum=array0;float aver,sum=array0;for(i=1;i10;i+)for(i=1;i10;i+) sum+=arrayi;sum+=arrayi;aver=sum/10;aver=sum/10;return aver;return aver; #include #include void main()void main() float average(float array10);float average(float array10);float score10,aver;float score10,aver;int i;int i;printf(input 10 scores:n);printf(input 10 scores:n);for(i=0;i10;i+)for(i=0;i10;i+) printf(score%d=,i); printf(score%d=,i); scanf(%f,&scorei); scanf(%f,&scorei); aver=average(score);aver=average(score);printf(naverage score is %5.2fn,aver);printf(naverage score is %5.2fn,aver); 只求只求只求只求前前前前n n( (动态动态动态动态输入输入输入输入) )个学生个学生个学生个学生的平均成绩的平均成绩的平均成绩的平均成绩例例例例10 10 有一个一维数组有一个一维数组有一个一维数组有一个一维数组scorescore,内放,内放,内放,内放1010个学生成绩,求平均成个学生成绩,求平均成个学生成绩,求平均成个学生成绩,求平均成绩绩绩绩float score10,avg;float score10,avg;给数组给数组给数组给数组scorescore赋初值赋初值赋初值赋初值avg=average(score);avg=average(score);output avg;output avg;i=0 to 9i=0 to 9sum+=arrayi;sum+=arrayi;return sum/10;return sum/10;average(float array10)average(float array10),n),n); ;,int ,int n)n)n nn nfloat average(float average(float array10float array10) ) int i;int i;float aver,sum=array0;float aver,sum=array0;for(i=1;i10;i+)for(i=1;i10;i+) sum+=arrayi;sum+=arrayi;aver=sum/10;aver=sum/10;return aver;return aver; ,int ,int n n) )n nn n#include #include void main()void main() float average(float array10);float average(float array10);float score10,aver;float score10,aver;int i;int i;printf(input 10 scores:n);printf(input 10 scores:n);for(i=0;i10;i+)for(i=0;i10;i+) printf(score%d=,i); printf(score%d=,i); scanf(%f,&scorei); scanf(%f,&scorei); aver=average(score);aver=average(score);printf(naverage score is %5.2fn,aver);printf(naverage score is %5.2fn,aver); ,int ,int n n););,n),n)scanf(%d,&n);scanf(%d,&n);,n;,n;求求求求n nmm个学个学个学个学生的平均成绩生的平均成绩生的平均成绩生的平均成绩(1 1)形参数组和实参数组的类型须一致,形参数组和实参数组的类型须一致,形参数组和实参数组的类型须一致,形参数组和实参数组的类型须一致,否则引起错误。否则引起错误。否则引起错误。否则引起错误。 (2 2)形参数组和实参数组的长度可以不同,因为在调用时,形参数组和实参数组的长度可以不同,因为在调用时,形参数组和实参数组的长度可以不同,因为在调用时,形参数组和实参数组的长度可以不同,因为在调用时,只传送首地址而不检查形参数组的长度。只传送首地址而不检查形参数组的长度。只传送首地址而不检查形参数组的长度。只传送首地址而不检查形参数组的长度。当形参数组的长当形参数组的长当形参数组的长当形参数组的长度与实参数组不一致时,虽不至于出现语法错误度与实参数组不一致时,虽不至于出现语法错误度与实参数组不一致时,虽不至于出现语法错误度与实参数组不一致时,虽不至于出现语法错误( (编译能编译能编译能编译能通过通过通过通过) ),但程序执行结果将与实际不符,这种现象应予以,但程序执行结果将与实际不符,这种现象应予以,但程序执行结果将与实际不符,这种现象应予以,但程序执行结果将与实际不符,这种现象应予以避免的。避免的。避免的。避免的。 (3 3)在函数形参表中,允许不给出形参数组的长度在函数形参表中,允许不给出形参数组的长度在函数形参表中,允许不给出形参数组的长度在函数形参表中,允许不给出形参数组的长度,此时此时此时此时形参数组自动取和实参数组相同的长度,形参数组自动取和实参数组相同的长度,形参数组自动取和实参数组相同的长度,形参数组自动取和实参数组相同的长度,或再多用一个变或再多用一个变或再多用一个变或再多用一个变量做参数来表示数组元素的个数。量做参数来表示数组元素的个数。量做参数来表示数组元素的个数。量做参数来表示数组元素的个数。float average(float array)float average(float array) int i;int i;float aver,sum=array0;float aver,sum=array0;for(i=1;i10;i+)for(i=1;i10;i+)sum+=arrayi;sum+=arrayi;aver=sum/10;aver=sum/10; return aver;return aver; (4 4)多维数组也可以作为函数的参数。多维数组也可以作为函数的参数。多维数组也可以作为函数的参数。多维数组也可以作为函数的参数。在函数定义时对形参在函数定义时对形参在函数定义时对形参在函数定义时对形参数组可以指定每一维的长度,也可省去第一维的长度。数组可以指定每一维的长度,也可省去第一维的长度。数组可以指定每一维的长度,也可省去第一维的长度。数组可以指定每一维的长度,也可省去第一维的长度。例例例例8-13 8-13 有一个有一个有一个有一个3434的矩阵,求所有元素中的最大值的矩阵,求所有元素中的最大值的矩阵,求所有元素中的最大值的矩阵,求所有元素中的最大值#include #include void main()void main() int max_value(int array4);int max_value(int array4);int int a34=1,3,5,7,2,4,6,8,15,17,34,12;a34=1,3,5,7,2,4,6,8,15,17,34,12;printf(max value is %dn,printf(max value is %dn,max_value(a)max_value(a);); int max_value(int array4)int max_value(int array4) int i,j,max=array00;int i,j,max=array00;for(i=0;i3;i+)for(i=0;i3;i+)for(j=0;j4;j+)for(j=0;jmax)if(arrayijmax)max=arrayij;max=arrayij;return max;return max; C语言的函数定义是互相平行的、独立的。语言的函数定义是互相平行的、独立的。也就是说,在定义函数时,一个函数内不能也就是说,在定义函数时,一个函数内不能包含另一个函数包含另一个函数嵌套定义嵌套定义 但是但是C语言允许在调用一个函数的过程中,语言允许在调用一个函数的过程中,又调用另一个函数。又调用另一个函数。嵌套调用嵌套调用#include #include void main()void main() float average(float array10,int n)float average(float array10,int n) int i;int i;float aver,sum=array0;float aver,sum=array0;for(i=1;in;i+) for(i=1;in;i+) sum+=arrayi;sum+=arrayi;aver=sum/n;aver=sum/n;return aver;return aver; float score10,aver;float score10,aver;int i,n;int i,n;printf(input 10 scores:n);printf(input 10 scores:n);for(i=0;i10;i+)for(i=0;i10;i+) printf(score%d=,i); scanf(%f,&scorei); printf(score%d=,i); scanf(%f,&scorei);printf(Please input n:);printf(Please input n:);scanf(%d,&n);scanf(%d,&n);aver=average(score,n);aver=average(score,n);printf(naverage score is %5.2fn,aver);printf(naverage score is %5.2fn,aver); line line 函数函数函数函数main main 函数函数函数函数 star star 函数函数函数函数调调调调用用用用 结束结束结束结束调用调用调用调用#include #include void star(int);void star(int);void line();void line();void main()void main() star(20);star(20); printf(n); printf(n); void star(int d)void star(int d) int i; int i; for(i=1;id;i+) for(i=1;i10) if (i10) line();line(); else printf(*); else printf(*); void line()void line() printf(-); printf(-);回推回推回推回推递推递推递推递推例例例例1111年龄问题年龄问题年龄问题年龄问题: :有有有有5 5个人坐在一起,问第个人坐在一起,问第个人坐在一起,问第个人坐在一起,问第5 5个人多少岁?他说比个人多少岁?他说比个人多少岁?他说比个人多少岁?他说比第第第第4 4个人大个人大个人大个人大2 2岁岁岁岁。问第。问第。问第。问第4 4个人多少岁,他说比个人多少岁,他说比个人多少岁,他说比个人多少岁,他说比第第第第3 3个人大个人大个人大个人大2 2岁岁岁岁。问第。问第。问第。问第3 3个人多少岁,又说比第个人多少岁,又说比第个人多少岁,又说比第个人多少岁,又说比第2 2个人大个人大个人大个人大2 2岁岁岁岁。问第。问第。问第。问第2 2个人,说比个人,说比个人,说比个人,说比第第第第1 1个人个人个人个人大大大大2 2岁岁岁岁。最后问第。最后问第。最后问第。最后问第1 1个人,个人,个人,个人,他说是他说是他说是他说是1010岁岁岁岁。请问第。请问第。请问第。请问第5 5个人多少岁。个人多少岁。个人多少岁。个人多少岁。递归调用递归调用一个函数在它的函数体内直接或一个函数在它的函数体内直接或者间接调用者间接调用它自身它自身。这种函数称为递归函数。这种函数称为递归函数。N要解决的问题可以转换为一个新的要解决的问题可以转换为一个新的问题,而这个新的问题的解决与原来问题,而这个新的问题的解决与原来问题的解法相同,只是所处理的对象问题的解法相同,只是所处理的对象有规律的变化,递增或递减。有规律的变化,递增或递减。N可以应用这个规律的递归结束条件可以应用这个规律的递归结束条件N要有一个明确的递归结束条件要有一个明确的递归结束条件算法描述为:算法描述为: if(递归中止条件递归中止条件) return (条件终止时的值条件终止时的值) else return 递归公式递归公式#include int age(int n) int c; if(n=1) c=10; else c=age(n-1)+2; return(c);void main() printf(%dn,age(5);递归终止条件递归终止条件递归终止条件递归终止条件递归公式递归公式递归公式递归公式mainage(5)age(4)age(3)age(2)age(1)end例例例例1212: 用递归法计算用递归法计算用递归法计算用递归法计算n!n!分析分析:用递归法计算用递归法计算n!可用下述公式表示:可用下述公式表示: n!=1 (n=0,1) n!=n(n-1)! (n1)long ff (int n) long f; if(n0) printf(n0,input error); else if(n=0|n=1) f=1; else f=ff(n-1)*n; return(f);#include #include void main()void main() long ff(int);long ff(int); int a; int a; printf(a=); printf(a=); scanf(%d,&a); scanf(%d,&a); printf(%d!=%ldn,a, printf(%d!=%ldn,a,ff(a)ff(a);); 例例13Hanoi(汉诺塔)问题汉诺塔)问题:这是一个古典的数学问题,:这是一个古典的数学问题,是一个只有用递归方法(而不能用其他方法)解决的问是一个只有用递归方法(而不能用其他方法)解决的问题。问题是这样的:古代有一个梵塔,塔内有题。问题是这样的:古代有一个梵塔,塔内有3个座个座A、B、C,开始时,开始时A座上有座上有64个盘子,盘子大小不等,大的个盘子,盘子大小不等,大的在下,小的在上。有一个老和尚想把这在下,小的在上。有一个老和尚想把这64个盘子从个盘子从A座座移到移到C座上,但每次只允许移动一个盘子,且在移动过程座上,但每次只允许移动一个盘子,且在移动过程中在中在3个坐上都始终保持大盘在下,小盘在上。在移动过个坐上都始终保持大盘在下,小盘在上。在移动过程中可以利用程中可以利用B座,要求编程打印出移动的步骤。座,要求编程打印出移动的步骤。123123123123hanoi(int n,char one,char two,char three)n=1n=1move(one,threemove(one,three) )move(one,three)move(one,three)hanoihanoi(n-1,one,three,two)(n-1,one,three,two)hanoihanoi(n-1,two,one,three)(n-1,two,one,three)T TF Fmove(char x,char y)printf(“%c-%cn”,x,y);printf(“%c-%cn”,x,y);例例13Hanoi(汉诺塔)问题:汉诺塔)问题:#include void move(char x,char y)printf(%c-%cn,x,y);void hanoi(int n,char one,char two,char three) if(n=1) move(one,three);else hanoi(n-1,one,three,two);move(one,three);hanoi(n-1,two,one,three);void main()int m;printf(input the number of disks:);scanf(%d,&m);printf( the step to moving %3d diskes:n,m);hanoi(m,A,B,C);对递归函数概括如下:对递归函数概括如下:对递归函数概括如下:对递归函数概括如下: 有些问题既可以用递归的方法解决,也可以用递推有些问题既可以用递归的方法解决,也可以用递推有些问题既可以用递归的方法解决,也可以用递推有些问题既可以用递归的方法解决,也可以用递推的方法解决。有些问题不用递归是难以得到结果的。的方法解决。有些问题不用递归是难以得到结果的。的方法解决。有些问题不用递归是难以得到结果的。的方法解决。有些问题不用递归是难以得到结果的。 递归函数算法清晰,代码简练递归函数算法清晰,代码简练递归函数算法清晰,代码简练递归函数算法清晰,代码简练 从理论上讲,递归函数似乎很复杂,其实它是编程从理论上讲,递归函数似乎很复杂,其实它是编程从理论上讲,递归函数似乎很复杂,其实它是编程从理论上讲,递归函数似乎很复杂,其实它是编程中的一类问题的算法,最为直接中的一类问题的算法,最为直接中的一类问题的算法,最为直接中的一类问题的算法,最为直接 C C编译系统对递归函数的自调用次数没有限制,但当编译系统对递归函数的自调用次数没有限制,但当编译系统对递归函数的自调用次数没有限制,但当编译系统对递归函数的自调用次数没有限制,但当递归层次过多时,可能会引起内存不足而造成运行出错,递归层次过多时,可能会引起内存不足而造成运行出错,递归层次过多时,可能会引起内存不足而造成运行出错,递归层次过多时,可能会引起内存不足而造成运行出错,尤其时函数内部定义较多的变量和较大的数组时尤其时函数内部定义较多的变量和较大的数组时尤其时函数内部定义较多的变量和较大的数组时尤其时函数内部定义较多的变量和较大的数组时采用递归方式采用递归方式采用递归方式采用递归方式实现实现实现实现二分查找二分查找二分查找二分查找N 函数调用时,实参和形参类型不一致函数调用时,实参和形参类型不一致函数调用时,实参和形参类型不一致函数调用时,实参和形参类型不一致N 在值传递中,企图用形参值的改变影响实参在值传递中,企图用形参值的改变影响实参在值传递中,企图用形参值的改变影响实参在值传递中,企图用形参值的改变影响实参值值值值N 传递数据名时传递为数组元素值传递数据名时传递为数组元素值传递数据名时传递为数组元素值传递数据名时传递为数组元素值N 对函数进行嵌套定义对函数进行嵌套定义对函数进行嵌套定义对函数进行嵌套定义N 对函数递归调用时,落掉递归结束条件对函数递归调用时,落掉递归结束条件对函数递归调用时,落掉递归结束条件对函数递归调用时,落掉递归结束条件N 在在在在C C语言中,参数的值传递,具有如下特点:语言中,参数的值传递,具有如下特点:语言中,参数的值传递,具有如下特点:语言中,参数的值传递,具有如下特点:实参与实参与实参与实参与形参各自占据独立的存储单元;形参各自占据独立的存储单元;形参各自占据独立的存储单元;形参各自占据独立的存储单元; 调用时,将实参的值传调用时,将实参的值传调用时,将实参的值传调用时,将实参的值传入形参单元入形参单元入形参单元入形参单元; 在被调用的函数内,访问相应的形参单元在被调用的函数内,访问相应的形参单元在被调用的函数内,访问相应的形参单元在被调用的函数内,访问相应的形参单元; 函数调用结束时,释放形参单元函数调用结束时,释放形参单元函数调用结束时,释放形参单元函数调用结束时,释放形参单元N 参数的地址传递有什么特点?参数的地址传递有什么特点?参数的地址传递有什么特点?参数的地址传递有什么特点?N C C语言中,函数可以嵌套调用,不可以嵌套定义语言中,函数可以嵌套调用,不可以嵌套定义语言中,函数可以嵌套调用,不可以嵌套定义语言中,函数可以嵌套调用,不可以嵌套定义N 函数递归调用指对函数自身的调用,算法描述为:函数递归调用指对函数自身的调用,算法描述为:函数递归调用指对函数自身的调用,算法描述为:函数递归调用指对函数自身的调用,算法描述为: if(if(递归中止条件递归中止条件递归中止条件递归中止条件) return () return (条件终止时的值条件终止时的值条件终止时的值条件终止时的值) ) else return else return 递归公式递归公式递归公式递归公式教学内容教学内容变量的作用域与存储类别、内部变量的作用域与存储类别、内部函数和外部函数函数和外部函数教学目标教学目标应知应知变量的作用域与生存期变量的作用域与生存期变量的存储类别变量的存储类别宏定义和文件包含宏定义和文件包含程序中变量的作用范围程序中变量的作用范围能够分析程序中静态变量的值能够分析程序中静态变量的值会正确使用宏定义会正确使用宏定义难点难点 静态变量在程序中的作用静态变量在程序中的作用O 变量变量变量是对程序中数据的存储空间的抽象变量是对程序中数据的存储空间的抽象静态存储方式静态存储方式静态存储方式静态存储方式动态存储方式动态存储方式动态存储方式动态存储方式自动型自动型自动型自动型(auto)(auto)静态型静态型静态型静态型(static)(static)寄存器型寄存器型寄存器型寄存器型(registic)(registic)外部型外部型外部型外部型(extern)(extern)指在程序运行期间由系统分指在程序运行期间由系统分指在程序运行期间由系统分指在程序运行期间由系统分配配配配固定的固定的固定的固定的存储空间的方式存储空间的方式存储空间的方式存储空间的方式指在程序运行期间由系统指在程序运行期间由系统指在程序运行期间由系统指在程序运行期间由系统根据需要根据需要根据需要根据需要进行动态分配存储空间的方式进行动态分配存储空间的方式进行动态分配存储空间的方式进行动态分配存储空间的方式int sum; auto int a,b,c;register int i;static float x,y;将变量分为将变量分为将变量分为将变量分为intint、floatfloat等等类型等等类型等等类型等等类型全局变量全局变量全局变量全局变量局部变量局部变量局部变量局部变量指在程序指在程序指在程序指在程序整个运行期间整个运行期间整个运行期间整个运行期间都起作用都起作用都起作用都起作用指在程序指在程序指在程序指在程序局部运行期间局部运行期间局部运行期间局部运行期间都起作用都起作用都起作用都起作用数据类型:数据类型:数据类型:数据类型:变量所持有的数据的性质(操作属性)变量所持有的数据的性质(操作属性)变量所持有的数据的性质(操作属性)变量所持有的数据的性质(操作属性)生存期:生存期:生存期:生存期:变量在内存中存在的某一时间范围(数据的存变量在内存中存在的某一时间范围(数据的存变量在内存中存在的某一时间范围(数据的存变量在内存中存在的某一时间范围(数据的存储类别)储类别)储类别)储类别)作用域:作用域:作用域:作用域:变量能够起作用的程序空间范围变量能够起作用的程序空间范围变量能够起作用的程序空间范围变量能够起作用的程序空间范围int f1(int a,int b)int c,d;.float f2(float x,float y)int c,d; float t; . .main()int x,y;float a,b;.局部变量:局部变量:函数内部或复合语句内函数内部或复合语句内定义的变量是局部变量,定义的变量是局部变量,也称为内部变量。也称为内部变量。a,b,c,da,b,c,d在此范围内有效在此范围内有效在此范围内有效在此范围内有效x,y,c,dx,y,c,d在此范围在此范围在此范围在此范围内有效内有效内有效内有效t t在此在此在此在此范围内范围内范围内范围内有效有效有效有效x,y,a,bx,y,a,b在此范围在此范围在此范围在此范围内有效内有效内有效内有效p主函数定义的变量,也只在主函数内有主函数定义的变量,也只在主函数内有主函数定义的变量,也只在主函数内有主函数定义的变量,也只在主函数内有效。主函数也不能使用其他函数中定义的效。主函数也不能使用其他函数中定义的效。主函数也不能使用其他函数中定义的效。主函数也不能使用其他函数中定义的变量,从这一点上讲,函数都是平等的。变量,从这一点上讲,函数都是平等的。变量,从这一点上讲,函数都是平等的。变量,从这一点上讲,函数都是平等的。p不同函数中变量可以同名,互不干扰。不同函数中变量可以同名,互不干扰。不同函数中变量可以同名,互不干扰。不同函数中变量可以同名,互不干扰。p形参也是局部变量形参也是局部变量形参也是局部变量形参也是局部变量p在复合语句中也可定义变量,它们的作在复合语句中也可定义变量,它们的作用域同样只在所定义的段落内部。用域同样只在所定义的段落内部。全局变量:全局变量:函数之外定义的变量叫全局变量,也称为外部变量。函数之外定义的变量叫全局变量,也称为外部变量。说明:说明:全局变量从全局变量从定义处开始起作用,直到整个源文件结束定义处开始起作用,直到整个源文件结束,此,此后出现的函数都可使用。它实际上实现了函数之间数据沟通的方后出现的函数都可使用。它实际上实现了函数之间数据沟通的方式,增强了各模块的联系。但也降低了模块自身的独立性。式,增强了各模块的联系。但也降低了模块自身的独立性。int p=1,q=5; /*全局变量全局变量p,q*/float f1(int a)/*p,q从此处开始作用且作用域一直延续到程序结束从此处开始作用且作用域一直延续到程序结束*/ int b,c; char c1,c2; /*外部变量外部变量c1,c2,它们从这里,它们从这里 开始发挥作用开始发挥作用*/char f2(x,y) /*定义函数定义函数f2*/ char c1,c2; /*注意此处的局部变量注意此处的局部变量c1,c2将将 屏蔽外层的全局变屏蔽外层的全局变量,即,在量,即,在 f2函数中凡是提到函数中凡是提到c1,c2,均是,均是 指的局部变量指的局部变量c1,c2*/ #include #include int x=2,y=3;int x=2,y=3;void main()void main() void swap();void swap();swap();swap();printf(printf(交换后交换后交换后交换后:n);:n); printf(x=%d,y=%dn, x,y); printf(x=%d,y=%dn, x,y); void swap()void swap() int temp; int temp;temp=x;temp=x;x=y;x=y;y=temp;y=temp; x=10;y=5;x=10;y=5;例例例例14:14:使用全局变量使用全局变量使用全局变量使用全局变量实现两个整型数值的实现两个整型数值的实现两个整型数值的实现两个整型数值的交换。交换。交换。交换。O 限制了函数的通用性限制了函数的通用性限制了函数的通用性限制了函数的通用性O 损害了程序的清晰度损害了程序的清晰度损害了程序的清晰度损害了程序的清晰度O 降低了内存的利用率降低了内存的利用率降低了内存的利用率降低了内存的利用率 如果在同一个源文件如果在同一个源文件如果在同一个源文件如果在同一个源文件中,外部变量与局部中,外部变量与局部中,外部变量与局部中,外部变量与局部变量同名,则在局部变量同名,则在局部变量同名,则在局部变量同名,则在局部变量的范围内,变量的范围内,变量的范围内,变量的范围内,外部外部外部外部变量被变量被变量被变量被“ “屏蔽屏蔽屏蔽屏蔽” ”动态存储方式动态存储方式动态存储方式动态存储方式:程序运行期间据需要动态分配存储空间的方式。程序运行期间据需要动态分配存储空间的方式。程序运行期间据需要动态分配存储空间的方式。程序运行期间据需要动态分配存储空间的方式。静态存储方式:静态存储方式:静态存储方式:静态存储方式:在程序运行期间分配固定存储空间的方式。在程序运行期间分配固定存储空间的方式。在程序运行期间分配固定存储空间的方式。在程序运行期间分配固定存储空间的方式。动态存储区动态存储区静态存储区静态存储区程序区程序区 数据分别存放在静态存储区和动态存储区数据分别存放在静态存储区和动态存储区数据分别存放在静态存储区和动态存储区数据分别存放在静态存储区和动态存储区 全局变量全部存放在静态存储区全局变量全部存放在静态存储区全局变量全部存放在静态存储区全局变量全部存放在静态存储区中,在程序中,在程序中,在程序中,在程序开始执行时给全局变量分配存储区,程序执行开始执行时给全局变量分配存储区,程序执行开始执行时给全局变量分配存储区,程序执行开始执行时给全局变量分配存储区,程序执行完毕就释放。在程序执行过程中它们占据固定完毕就释放。在程序执行过程中它们占据固定完毕就释放。在程序执行过程中它们占据固定完毕就释放。在程序执行过程中它们占据固定的存储单元,而不是动态地进行分配和释放的存储单元,而不是动态地进行分配和释放的存储单元,而不是动态地进行分配和释放的存储单元,而不是动态地进行分配和释放 在在在在动态存储区中动态存储区中动态存储区中动态存储区中存放以下数据:存放以下数据:存放以下数据:存放以下数据:函数形式参函数形式参函数形式参函数形式参数数数数、自动变量自动变量自动变量自动变量、函数调用时的现场保护和返回函数调用时的现场保护和返回函数调用时的现场保护和返回函数调用时的现场保护和返回地址地址地址地址等。对以上这些数据,在函数调用开始时等。对以上这些数据,在函数调用开始时等。对以上这些数据,在函数调用开始时等。对以上这些数据,在函数调用开始时分配动态存储空间,函数结束时释放这些空间。分配动态存储空间,函数结束时释放这些空间。分配动态存储空间,函数结束时释放这些空间。分配动态存储空间,函数结束时释放这些空间。 在在在在复合语句内复合语句内复合语句内复合语句内或或或或函数内函数内函数内函数内定义变量时,使用定义变量时,使用定义变量时,使用定义变量时,使用atuoatuo说明符或省略存储类型说明符,所定义的说明符或省略存储类型说明符,所定义的说明符或省略存储类型说明符,所定义的说明符或省略存储类型说明符,所定义的变量就是变量就是变量就是变量就是autoauto变量。变量。变量。变量。autoauto类型的局部变量类型的局部变量类型的局部变量类型的局部变量存储在动态存储区存储在动态存储区存储在动态存储区存储在动态存储区,动,动,动,动态分配存储空间,可以节省存储空间。态分配存储空间,可以节省存储空间。态分配存储空间,可以节省存储空间。态分配存储空间,可以节省存储空间。 autoauto变量使用说明:变量使用说明:变量使用说明:变量使用说明:N 同一函数的两次调用之间,不保留值。同一函数的两次调用之间,不保留值。同一函数的两次调用之间,不保留值。同一函数的两次调用之间,不保留值。N 自动变量如定义时赋初值自动变量如定义时赋初值自动变量如定义时赋初值自动变量如定义时赋初值( (在执行阶段在执行阶段在执行阶段在执行阶段) ),则每次调用函数都赋一次初值。则每次调用函数都赋一次初值。则每次调用函数都赋一次初值。则每次调用函数都赋一次初值。 static static 类型的静态变量:类型的静态变量:类型的静态变量:类型的静态变量:存储在静态存储区存储在静态存储区存储在静态存储区存储在静态存储区,静,静,静,静态分配存储空间,态分配存储空间,态分配存储空间,态分配存储空间,其生存期为整个程序的运行区间其生存期为整个程序的运行区间其生存期为整个程序的运行区间其生存期为整个程序的运行区间。对静态变量是对静态变量是对静态变量是对静态变量是在编译时在编译时在编译时在编译时赋初值的,即只赋初值一次赋初值的,即只赋初值一次赋初值的,即只赋初值一次赋初值的,即只赋初值一次 如在定义局部变量时不赋初值的话,则如在定义局部变量时不赋初值的话,则如在定义局部变量时不赋初值的话,则如在定义局部变量时不赋初值的话,则对静态变量对静态变量对静态变量对静态变量来说,编译时自动赋初值来说,编译时自动赋初值来说,编译时自动赋初值来说,编译时自动赋初值0 0或空字符或空字符或空字符或空字符。而对。而对。而对。而对自动变量自动变量自动变量自动变量而言,如果不赋初值而言,如果不赋初值而言,如果不赋初值而言,如果不赋初值它就是一个不确定的值它就是一个不确定的值它就是一个不确定的值它就是一个不确定的值#include #include void main()void main() int x;int x;static y;static y;printf(x=%d,y=%dn,x,y);printf(x=%d,y=%dn,x,y); #include #include void main()void main() int f(int);int f(int);int a=2,i;int a=2,i;for(i=0;i3;i+)for(i=0;i3;i+) printf(%d,f(a); printf(%d,f(a); int f(int a)int f(int a) auto int b=0; auto int b=0; static int c=3; static int c=3; b=b+1; b=b+1; c=c+1; c=c+1; return(a+b+c); return(a+b+c); 调用时的初值调用时的初值调用后的初值调用后的初值bcbca+b+cN.1N.2N.30 03 31 14 47 70 04 41 15 58 80 05 51 16 69 9registerregister类型的局部变量也属于类型的局部变量也属于类型的局部变量也属于类型的局部变量也属于autoauto变量。变量。变量。变量。其区别在于其区别在于其区别在于其区别在于: :用用用用registerregister说明的变量建议编译程序将变量的值存放在说明的变量建议编译程序将变量的值存放在说明的变量建议编译程序将变量的值存放在说明的变量建议编译程序将变量的值存放在CPUCPU的的的的寄存器中,而不是内存中。存取速度最快,适用于使用频寄存器中,而不是内存中。存取速度最快,适用于使用频寄存器中,而不是内存中。存取速度最快,适用于使用频寄存器中,而不是内存中。存取速度最快,适用于使用频繁的变量,但受寄存器数目的限制。繁的变量,但受寄存器数目的限制。繁的变量,但受寄存器数目的限制。繁的变量,但受寄存器数目的限制。#include #include void main()void main() registerregister int i; int i; /*i/*i由于变化频繁定义为寄存由于变化频繁定义为寄存由于变化频繁定义为寄存由于变化频繁定义为寄存器变量器变量器变量器变量*/*/ long s=1;long s=1;for (i=1; i=100; i+)for (i=1; i=100; i+)s=s*i;s=s*i;printf(s=%dn,s);printf(s=%dn,s); 注意事项:注意事项:注意事项:注意事项:1.使用使用使用使用registerregister变量的方针是:变量的方针是:变量的方针是:变量的方针是:“ “快定义、快快定义、快快定义、快快定义、快使用、快释放使用、快释放使用、快释放使用、快释放” ”2. 全局变量全局变量全局变量全局变量不能定义为寄存器变量不能定义为寄存器变量不能定义为寄存器变量不能定义为寄存器变量3. 寄存器变量运行定义的个数与计算机寄存器变量运行定义的个数与计算机寄存器变量运行定义的个数与计算机寄存器变量运行定义的个数与计算机CPUCPU中寄存器个数有关,还与编译系统有关,一中寄存器个数有关,还与编译系统有关,一中寄存器个数有关,还与编译系统有关,一中寄存器个数有关,还与编译系统有关,一般为般为般为般为2 2个个个个4. 现代的优化编译系统能够识别使用频繁的现代的优化编译系统能够识别使用频繁的现代的优化编译系统能够识别使用频繁的现代的优化编译系统能够识别使用频繁的变量,自动地将这些变量放在寄存器中,而变量,自动地将这些变量放在寄存器中,而变量,自动地将这些变量放在寄存器中,而变量,自动地将这些变量放在寄存器中,而不需程序中指定。不需程序中指定。不需程序中指定。不需程序中指定。mainmain函数中所用的函数中所用的函数中所用的函数中所用的A,BA,B变变变变量实际是在下文定义的,量实际是在下文定义的,量实际是在下文定义的,量实际是在下文定义的,此处用此处用此处用此处用externextern声明之,就声明之,就声明之,就声明之,就可保证提前使用它,从而可保证提前使用它,从而可保证提前使用它,从而可保证提前使用它,从而扩展了扩展了扩展了扩展了s s的作用域的作用域的作用域的作用域A,BA,B作为全局变作为全局变作为全局变作为全局变量在后部定义量在后部定义量在后部定义量在后部定义用用extern对变量加以声明,可以将其作用域扩展到整个对变量加以声明,可以将其作用域扩展到整个文件或多个文件。文件或多个文件。1.将变量作用域扩展到整个文件将变量作用域扩展到整个文件#include #include void main()void main() int max(int ,int);int max(int ,int);extern A,B;extern A,B; /声明外部变量声明外部变量声明外部变量声明外部变量printf(%dn,max(A,B);printf(%dn,max(A,B); int A=13,B=-8;int A=13,B=-8; /定义外部变量定义外部变量定义外部变量定义外部变量int max(int x,int y)int max(int x,int y) return xy?x:y; return xy?x:y; 用用extern对变量加以声明,可以将其作用域扩展到整个文件或多对变量加以声明,可以将其作用域扩展到整个文件或多个文件。个文件。2.将变量作用域扩展到多个文件将变量作用域扩展到多个文件例例例例5.14 5.14 阅读下面的程序,注意外部变量的使用方法阅读下面的程序,注意外部变量的使用方法阅读下面的程序,注意外部变量的使用方法阅读下面的程序,注意外部变量的使用方法/ /源文件源文件源文件源文件f1.c/f1.c/#include #include extern int a=5; extern int a=5; /定义外部变量,定义外部变量,定义外部变量,定义外部变量,externextern可以缺省可以缺省可以缺省可以缺省char c1=a,c2=b; char c1=a,c2=b; /定义外部变量定义外部变量定义外部变量定义外部变量void main()void main() extern int b; extern int b; /*/*外部变量外部变量外部变量外部变量b b的定义在后,使用在前,的定义在后,使用在前,的定义在后,使用在前,的定义在后,使用在前,必须用必须用必须用必须用externextern进行声明进行声明进行声明进行声明*/*/char c2=B;char c2=B;printf(%c n,c1-32);printf(%c n,c1-32);printf(“%c,%dn”,c2,b*b); printf(“%c,%dn”,c2,b*b); /局部变量局部变量局部变量局部变量c2c2起作用起作用起作用起作用fact();fact(); int b=2; int b=2; /定义外部变量定义外部变量定义外部变量定义外部变量#include #include extern int a; extern int a; /*/*使用另一个源使用另一个源使用另一个源使用另一个源文件中定义的外部变量必须进行文件中定义的外部变量必须进行文件中定义的外部变量必须进行文件中定义的外部变量必须进行应用性声明应用性声明应用性声明应用性声明*/*/void fact()void fact() int k,p=1;int k,p=1;for(k=1;k=a;k+)for(k=1;k=a;k+)p*=k;p*=k;printf(%d!=%dn,a,p)printf(%d!=%dn,a,p); ; externextern有两种声明形式:有两种声明形式:有两种声明形式:有两种声明形式:O定义性声明:定义性声明:定义性声明:定义性声明:是为了建立实体,即建立变量的存储是为了建立实体,即建立变量的存储是为了建立实体,即建立变量的存储是为了建立实体,即建立变量的存储空间空间空间空间 extern extern 类型类型类型类型 变量名变量名变量名变量名=初始化表达式初始化表达式初始化表达式初始化表达式 ;O引用性声明引用性声明引用性声明引用性声明:是为了建立标识符与实体之间的联系:是为了建立标识符与实体之间的联系:是为了建立标识符与实体之间的联系:是为了建立标识符与实体之间的联系 extern extern 类型类型类型类型 变量名;变量名;变量名;变量名;O两者区别如下:两者区别如下:两者区别如下:两者区别如下:定义性声明一定是在外部,引用性声明不限于外定义性声明一定是在外部,引用性声明不限于外定义性声明一定是在外部,引用性声明不限于外定义性声明一定是在外部,引用性声明不限于外部,只要在使用该外部变量前声明即可部,只要在使用该外部变量前声明即可部,只要在使用该外部变量前声明即可部,只要在使用该外部变量前声明即可 定义性声明可以初始化,引用性声明不能初始化定义性声明可以初始化,引用性声明不能初始化定义性声明可以初始化,引用性声明不能初始化定义性声明可以初始化,引用性声明不能初始化定义性声明在程序中只有一次,而引用性声明可定义性声明在程序中只有一次,而引用性声明可定义性声明在程序中只有一次,而引用性声明可定义性声明在程序中只有一次,而引用性声明可以有多次以有多次以有多次以有多次 存储类别存储类别存储类别存储类别 数据类型数据类型数据类型数据类型 变量名变量名变量名变量名 = =变量值变量值变量值变量值 变量的声明变量的声明(declaration)告知系统下面将要告知系统下面将要用到某一变量,并不分配存储空间及地址。(声明用到某一变量,并不分配存储空间及地址。(声明过程又称为引用性声明过程又称为引用性声明referencedeclaration)变量的定义变量的定义(definition)建立变量的物理存建立变量的物理存储空间,得到具体的存储地址。(定义过程又称为储空间,得到具体的存储地址。(定义过程又称为定义性声明定义性声明definingdeclaration)1 1、局部变量的存储类别、局部变量的存储类别auto自动变量自动变量没有指明存储类别时,隐含为没有指明存储类别时,隐含为auto。auto类型的局部变量存储在动态存储区。类型的局部变量存储在动态存储区。static静态局部变量静态局部变量类型的局部变量存储在类型的局部变量存储在静态存储静态存储区,静态分配存储空间,其生存期为整个程序区,静态分配存储空间,其生存期为整个程序的运行期间。的运行期间。register寄存器变量寄存器变量类型的局部变量存放在类型的局部变量存放在CPU的寄的寄存器中,存取速度最快。存器中,存取速度最快。2 2、全局变量的存储类别、全局变量的存储类别static静态外部变量静态外部变量只在本文件有效。只在本文件有效。extern外部变量外部变量允许其他文件引用。允许其他文件引用。 定义:定义:定义:定义:在对源程序进行编译之前,先对源程序在对源程序进行编译之前,先对源程序在对源程序进行编译之前,先对源程序在对源程序进行编译之前,先对源程序中的编译预处理命令进行处理;然后再将处理的中的编译预处理命令进行处理;然后再将处理的中的编译预处理命令进行处理;然后再将处理的中的编译预处理命令进行处理;然后再将处理的结果,和源程序一起进行编译,以得到目标代码。结果,和源程序一起进行编译,以得到目标代码。结果,和源程序一起进行编译,以得到目标代码。结果,和源程序一起进行编译,以得到目标代码。 在前面各章中,已多次使用过以在前面各章中,已多次使用过以在前面各章中,已多次使用过以在前面各章中,已多次使用过以“ “#”#”号开头的号开头的号开头的号开头的预处理命令。如包含命令预处理命令。如包含命令预处理命令。如包含命令预处理命令。如包含命令#include#include。在源程序。在源程序。在源程序。在源程序中这些命令都放在函数之外,中这些命令都放在函数之外,中这些命令都放在函数之外,中这些命令都放在函数之外, 而且一般都放在而且一般都放在而且一般都放在而且一般都放在源文件的前面,它们称为源文件的前面,它们称为源文件的前面,它们称为源文件的前面,它们称为预处理部分预处理部分预处理部分预处理部分。语言的三种预处理功能:语言的三种预处理功能:语言的三种预处理功能:语言的三种预处理功能: 宏定义(有参和无参)宏定义(有参和无参)宏定义(有参和无参)宏定义(有参和无参) 文件包含文件包含文件包含文件包含 条件编译条件编译条件编译条件编译预处理命令以符号预处理命令以符号预处理命令以符号预处理命令以符号“ “#”#”开头,末尾不加分号。开头,末尾不加分号。开头,末尾不加分号。开头,末尾不加分号。在语言源程序中允许用一个标识符来表示一个字在语言源程序中允许用一个标识符来表示一个字符串,符串,称为称为“宏宏”,它分为有参数和无参数两种。,它分为有参数和无参数两种。名名被定义为被定义为“宏宏”的标识符称为的标识符称为“宏名宏名”。宏代换宏代换编译预处理时,对程序中出现的编译预处理时,对程序中出现的“宏名宏名”,都用宏定义的字符串代换,称为,都用宏定义的字符串代换,称为“宏代换宏代换”或或“宏展开宏展开”。重点理解:重点理解:宏定义是由源程序中的宏定义命令设置的,即用宏定义是由源程序中的宏定义命令设置的,即用一组命令给出提前需要进行的数据处理。一组命令给出提前需要进行的数据处理。宏代换宏代换是由预处理程序自动执行的。是由预处理程序自动执行的。而而C语言的源程序是在于处理程序做完其任务后语言的源程序是在于处理程序做完其任务后由编译程序编译完成。由编译程序编译完成。无参宏的宏名后不带参数。无参宏的宏名后不带参数。格式:格式:#define标识符标识符字符串字符串#”表示这是一条预处理命令。凡是以表示这是一条预处理命令。凡是以“#”开头的均为预处理命令。开头的均为预处理命令。“define”宏定义命令。宏定义命令。“标识符标识符”定义的宏名,为所替代的串起个名定义的宏名,为所替代的串起个名字。字。“字符串字符串”可以是常数、表达式、格式串等。可以是常数、表达式、格式串等。例如:例如:在前面介绍过的符号常量的定义就是一种无在前面介绍过的符号常量的定义就是一种无参宏定义。参宏定义。#definePI3.1415926效果:效果:凡在程序中出现的凡在程序中出现的PI就代表就代表3.1415926这个这个数据,为很长的圆周率常数定义了一个符号来替代。数据,为很长的圆周率常数定义了一个符号来替代。此外,常对程序中反复使用的表达式进行宏定义。此外,常对程序中反复使用的表达式进行宏定义。#defineM(y*y+3*y)#includevoidmain()ints,y;printf(inputanumber:);scanf(%d,&y);s=3*M+4*M+5*M;printf(s=%dn,s);上例程序中首先进行宏定义,定义上例程序中首先进行宏定义,定义M为表达式为表达式(y*y+3*y),在,在s=3*M+4*M+5*M中作了宏调用。在预处理时经宏展开后中作了宏调用。在预处理时经宏展开后该语句变为:该语句变为:s=3*(y*y+3*y)+4*(y*y+3*y)+5*(y*y+3*y);注意:注意:在宏定义中表达式在宏定义中表达式(y*y+3*y)两边的括号不能少两边的括号不能少。否则会发。否则会发生错误。当进行以下定义后:生错误。当进行以下定义后:#defineMy*y+3*y在宏展开时将得到下述语句:在宏展开时将得到下述语句:s=3*y*y+3*y+4*y*y+3*y+5*y*y+3*y;显然与原题意要求不符。计算结果当然是错误的。显然与原题意要求不符。计算结果当然是错误的。因此在作因此在作宏定义时必须十分注意。应保证在宏代换之后不发生错误。宏定义时必须十分注意。应保证在宏代换之后不发生错误。所以,请一定将宏体作为一个整体对待,所以,请一定将宏体作为一个整体对待,定义它时就在两侧定义它时就在两侧加上括号加上括号,即使宏体只是一个独立的数据。这样良好的风格,即使宏体只是一个独立的数据。这样良好的风格可以避免很多隐蔽的失误。可以避免很多隐蔽的失误。又例:又例:#defineDATA#defineDATA(56.8*49.06-7856.8*49.06-78)#defineCITY“Xuzhou”#defineCITY“Xuzhou”说明:说明:1.宏定义是用宏名来表示一个字符串,在宏展开时又以该字符宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种串取代宏名,这只是一种简单的代换简单的代换,字符串中可以含任何,字符串中可以含任何字符,可以是常数,也可以是表达式,字符,可以是常数,也可以是表达式,预处理程序对它不作预处理程序对它不作任何检查。如有错误,只能在编译已被宏展开后的源程序时任何检查。如有错误,只能在编译已被宏展开后的源程序时发现。发现。2.宏定义不是说明或语句,在行末不必加分号,如加上分号则宏定义不是说明或语句,在行末不必加分号,如加上分号则分号是作为宏体的一部分,当宏展开时连分号也一起置换。分号是作为宏体的一部分,当宏展开时连分号也一起置换。例:例:#definePI3.1415926;main()area=PI*r*r;经过宏展开后,该语句为经过宏展开后,该语句为area=3.1415926;*r*r;说明:说明:3.宏定义必须写在函数之外,一般情况下其宏定义必须写在函数之外,一般情况下其作用域为宏定义命作用域为宏定义命令起到源程序结束令起到源程序结束。如要终止其作用域可使用。如要终止其作用域可使用#undef命令。命令。#definePI3.14159main()#undefPIf1().define和和undef搭配是用来规定宏的作用范围,现在搭配是用来规定宏的作用范围,现在PI只只在在main函数中有效,在函数中有效,在f1中无效。中无效。说明:说明:4.宏名在源程序中若出现在引号之中,则预处理程序不对其作宏名在源程序中若出现在引号之中,则预处理程序不对其作宏代换,只是将其作为普通字符串处理。宏代换,只是将其作为普通字符串处理。#include#defineOK100voidmain()printf(%dn,OK);printf(OK);printf(n);5.习惯上宏名用大写字母表示,以便于与变量区别,但这并非习惯上宏名用大写字母表示,以便于与变量区别,但这并非是规定。是规定。说明:说明:6.宏定义允许嵌套宏定义允许嵌套在宏定义的字符串中可以使用已经定义在宏定义的字符串中可以使用已经定义的宏名。在宏展开时由预处理程序层层代换。的宏名。在宏展开时由预处理程序层层代换。#definePI3.1415926#defineSPI*y*y/*PI是已定义的宏名是已定义的宏名*/对语句:对语句:printf(“%f”,S);在宏代换后变为:在宏代换后变为:printf(“%f”,3.1415926*y*y);7.使用宏定义的优点使用宏定义的优点(1)可提高源程序的可维护性。可提高源程序的可维护性。(2)可提高源程序的可移植性。可提高源程序的可移植性。(3)减少源程序中重复书写字符串的工作量。减少源程序中重复书写字符串的工作量。语言允许宏带有参数。在宏定义中的语言允许宏带有参数。在宏定义中的参数称为参数称为形式参数形式参数,在宏调用中的参在宏调用中的参数称为数称为实际参数实际参数。1 1、定义格式:、定义格式:#define宏名(形参表)宏名(形参表)字符串字符串其中其中“字符串字符串”是含有形参的表达式。是含有形参的表达式。2 2、调用方式:、调用方式:宏名(实参表)宏名(实参表)3 3、带参宏的展开:、带参宏的展开:在调用带参数的宏时,不仅要进行宏展开,在调用带参数的宏时,不仅要进行宏展开,同时要用宏调用提供的实参字符串,直接同时要用宏调用提供的实参字符串,直接替换宏定义命令行中的相应形参字符串,替换宏定义命令行中的相应形参字符串,非形参字符保持不变。非形参字符保持不变。例如:例如:#defineM(y)(y*y+3*y)/*宏定义宏定义*/:k=M(5);/*宏调用宏调用*/例如:例如:#include#definePI3.14#definecircum(r)2*PI*r#definearea(r)PI*r*rvoidmain() float ra,c,a; scanf(“%f”,&ra); c=circum(ra); a=area(ra); printf(“ra=%f,c=%f,a=%f”,ra,c,a); 说明:说明:1.带参宏定义中,宏名和形参表之间不能有空格出现。带参宏定义中,宏名和形参表之间不能有空格出现。例如:例如:把把#defineMAX(a,b)(ab)?a:b写为:写为:#defineMAX(a,b)(ab)?a:b将被认为是无参宏定义,将被认为是无参宏定义,宏名宏名MAX代表的是字符串:代表的是字符串:“(a,b)(ab)?a:b”。宏展开时,宏调用语句:宏展开时,宏调用语句:max=MAX(x,y);将变为:将变为:max=(a,b)(ab)?a:b(x,y);错误。错误。宏定义中,将把宏名之后空格后面的所有部分作为宏体。宏定义中,将把宏名之后空格后面的所有部分作为宏体。说明:说明:2.虽然带参宏与带参函数确实有相似之处,但不同之处更虽然带参宏与带参函数确实有相似之处,但不同之处更多,主要有以下几个方面:多,主要有以下几个方面:(1)调用有参函数时,先求出实参的值,然后再传递值给调用有参函数时,先求出实参的值,然后再传递值给形参,形参,有值的传递过程有值的传递过程;调用时,;调用时,形参要被分配相应存形参要被分配相应存储单元储单元。而展开有参宏时,只是将实参简单地置换形参,实参与而展开有参宏时,只是将实参简单地置换形参,实参与形参之间只是个值的对应关系,形参之间只是个值的对应关系,没有值的传递过程没有值的传递过程,只只是个符号替换过程;宏展开时,是个符号替换过程;宏展开时,不建立其形参的存储单不建立其形参的存储单元元。(2)在有参函数中,在有参函数中,形参是有类型的形参是有类型的,所以要求实参的类,所以要求实参的类型与其一致。型与其一致。而在有参宏中,而在有参宏中,形参是没有类型信息的形参是没有类型信息的,因此用于置换,因此用于置换的实参,什么类型都可以。有时,可利用有参宏的这一的实参,什么类型都可以。有时,可利用有参宏的这一特性,实现通用函数功能。特性,实现通用函数功能。说明:说明:(3)虽然使用有参函数,无论调用多少次,虽然使用有参函数,无论调用多少次,都不会使目标程序变长,但每次调用都要都不会使目标程序变长,但每次调用都要占用系统时间进行调用现场保护和现场恢占用系统时间进行调用现场保护和现场恢复;而使用有参宏,由于宏展开是在编译复;而使用有参宏,由于宏展开是在编译时进行的,所以不占运行时间,但是每引时进行的,所以不占运行时间,但是每引用用1次,都会使目标程序增大次,都会使目标程序增大1次。次。一般用宏来代表简短的表达式比较合适。一般用宏来代表简短的表达式比较合适。有些问题,用宏和函数都可以。有些问题,用宏和函数都可以。说明:说明:3.在宏定义中,字符串内的形参通常要用括号括起来以避免出错在宏定义中,字符串内的形参通常要用括号括起来以避免出错#define SQ(y) y*ymain() int a,sq; printf(“n input a number: ”); scanf(“%d”,&a); sq=SQ(a+1)*SQ(a+1); printf(“n sq=%d”,sq); 其运行结果为:其运行结果为:inputanumber:3sq=13结果:结果:inputanumber:3sq=256所以带参宏的原样替换操作决定宏体中参数两边的括号是所以带参宏的原样替换操作决定宏体中参数两边的括号是绝不能绝不能少的。少的。注意,注意,有时在参数两边加括号还不够,看下面程序:有时在参数两边加括号还不够,看下面程序:如果加上括号呢?如果加上括号呢?()()() )#defineSQ(y)(y)*(y)main()inta,sq;printf(inputanumber:);scanf(%d,&a);sq=160/SQ(a+1);printf(sq=%dn,sq);运行本程序如输入值仍为运行本程序如输入值仍为3时,希望结果为时,希望结果为10。但。但实际运行的结果如下:实际运行的结果如下:inputanumber:3sq=160本程序与前例相比,只本程序与前例相比,只把宏调用语句改为:把宏调用语句改为:sq=160/SQ(a+1);养成良好的宏定养成良好的宏定义习惯:义习惯:宏定义不仅应在宏定义不仅应在参数两侧加括号,参数两侧加括号,也应在整个字符也应在整个字符串外加括号串外加括号为什么?为什么?考察分析宏调用语句,可知在宏代换之后变为:考察分析宏调用语句,可知在宏代换之后变为:sq=160/(a+1)*(a+1);a为为3时,由于时,由于“/”和和“*”运算符优先级和结合性相同运算符优先级和结合性相同,则先作则先作160/(3+1)得得40,再作,再作40*(3+1)最后得最后得160。#define SQ(y) (y)*(y)main() int a,sq; printf(input a number: ); scanf(%d,&a); sq=160/SQ(a+1); printf(sq=%dn,sq); 为得到正确答案为得到正确答案应在宏定义中的整个字符串外加括号应在宏定义中的整个字符串外加括号,程程序修改如下:序修改如下:说明:说明:4.宏定义也可用来定义多个语句,在宏调用时,把这些语宏定义也可用来定义多个语句,在宏调用时,把这些语句又代换到源程序内。看下面的例子。句又代换到源程序内。看下面的例子。#define SSSV(s1,s2,s3,v) s1=l*w;s2=l*h;s3=w*h;v=w*l*h;main() int l=3,w=4,h=5,sa,sb,sc,vv; SSSV(sa,sb,sc,vv); printf(sa=%dnsb=%dnsc=%dnvv=%dn, sa,sb,sc,vv);程序第一行为宏定义,用宏名程序第一行为宏定义,用宏名SSSV表示表示4个赋值语句,个赋值语句,4个形参分别为个形参分别为4个赋值符左部的变量。在宏调用时,把个赋值符左部的变量。在宏调用时,把4个语句展开并用实参代替形参。使计算结果送入实参之中。个语句展开并用实参代替形参。使计算结果送入实参之中。“ “文件包含文件包含文件包含文件包含” ”处理:处理:处理:处理:指一个源文件可以将另外一个源文件的指一个源文件可以将另外一个源文件的指一个源文件可以将另外一个源文件的指一个源文件可以将另外一个源文件的全部内容包含进来。即将另外的文件包含到本文件之中。全部内容包含进来。即将另外的文件包含到本文件之中。全部内容包含进来。即将另外的文件包含到本文件之中。全部内容包含进来。即将另外的文件包含到本文件之中。其一般形式为:其一般形式为:其一般形式为:其一般形式为:#include“#include“文件名文件名文件名文件名”或或或或#include#include两种格式的区别仅在于:两种格式的区别仅在于:1)双引号:)双引号:系统先到当前目录下查找被包含文件,若没系统先到当前目录下查找被包含文件,若没找到,再到系统指定的找到,再到系统指定的“包含文件目录包含文件目录”(用户在配置环(用户在配置环境时设置)查境时设置)查2)尖括号:)尖括号:直接到系统指定的直接到系统指定的“包含文件目录包含文件目录”去查找。去查找。一般地说,使用双引号比较保险。一般地说,使用双引号比较保险。前面已多次用此命令包含过库函数的头文件。前面已多次用此命令包含过库函数的头文件。 #include stdio.h #include math.h这个头文件中就是四条语句,三句文件包含宏命令,一句这个头文件中就是四条语句,三句文件包含宏命令,一句函数的声明。函数的声明。可以把这些宏定义命令组成一个头文件,然后每个人都可以可以把这些宏定义命令组成一个头文件,然后每个人都可以可以把这些宏定义命令组成一个头文件,然后每个人都可以可以把这些宏定义命令组成一个头文件,然后每个人都可以用用用用#include#include命令将这些符号常量包含到自己所写的源文件中。命令将这些符号常量包含到自己所写的源文件中。命令将这些符号常量包含到自己所写的源文件中。命令将这些符号常量包含到自己所写的源文件中。这样每个人就可以不必重复定义这些符号常量,从而节省时这样每个人就可以不必重复定义这些符号常量,从而节省时这样每个人就可以不必重复定义这些符号常量,从而节省时这样每个人就可以不必重复定义这些符号常量,从而节省时间,并减少出错。间,并减少出错。间,并减少出错。间,并减少出错。例如:输入一个句子,统计单词个数。例如:输入一个句子,统计单词个数。首先编写一个头文件首先编写一个头文件:/*wang.h*/#include#defineTRUE1#defineFALSE0intisword(char);然后,编写程序然后,编写程序,在其中包含该头文件,在其中包含该头文件#includewang.h#includewang.hvoidmain()voidmain()intn=0;intn=0;charstr80;charstr80;gets(str);gets(str);n=isword(str);n=isword(str);printf(has%dwordsn,n);printf(has%dwordsn,n); intisword(charc)intisword(charc)inti,num=0,word=FALSE;inti,num=0,word=FALSE;for(i=0;ci!=0;i+)for(i=0;ci!=0;i+)if(ci=.|ci=n|ci=)if(ci=.|ci=n|ci=) word=FALSE;word=FALSE;elseif(!word)elseif(!word) word=TRUE;word=TRUE;num+;num+; returnnum;returnnum; 1、编译预处理时,预处理程序将查找指定的被包含文件,编译预处理时,预处理程序将查找指定的被包含文件,并将其复制到并将其复制到#include命令出现的位置上。命令出现的位置上。2、一个一个include命令只能指定一个被包含文件,命令只能指定一个被包含文件,若有多个若有多个文件要包含,则需用多个文件要包含,则需用多个include命令。命令。3、文件包含允许嵌套,即在一个被包含的文件中又可以包文件包含允许嵌套,即在一个被包含的文件中又可以包含另一个文件。含另一个文件。4、头文件的进一步理解:头文件的进一步理解:常用在文件头部的,被包含的文件,称为常用在文件头部的,被包含的文件,称为“标题文件标题文件”或或“头部文件头部文件”,常以,常以“h”(head)作为后缀,简称头文件。在)作为后缀,简称头文件。在头文件中,除可包含宏定义外,还可包含外部变量定义、结头文件中,除可包含宏定义外,还可包含外部变量定义、结构类型定义等。构类型定义等。5、一条包含命令,只能指定一个被包含文件。如果要包含一条包含命令,只能指定一个被包含文件。如果要包含n个文件,则要用个文件,则要用n条包含命令。条包含命令。N 混淆函数的声明与定义混淆函数的声明与定义混淆函数的声明与定义混淆函数的声明与定义N 参数传递时试图用形参影响实参参数传递时试图用形参影响实参参数传递时试图用形参影响实参参数传递时试图用形参影响实参N 函数调用时不理解返回值的意义函数调用时不理解返回值的意义函数调用时不理解返回值的意义函数调用时不理解返回值的意义N 静态变量在程序中的值静态变量在程序中的值静态变量在程序中的值静态变量在程序中的值N 全局变量与局部变量同名时起作用的那个变全局变量与局部变量同名时起作用的那个变全局变量与局部变量同名时起作用的那个变全局变量与局部变量同名时起作用的那个变量量量量N 在函数内部定义的变量为局部变量,只在在函数内部定义的变量为局部变量,只在本函数内有效,在函数外定义的变量为全本函数内有效,在函数外定义的变量为全局变量,作用域为从定义位置开始到本源局变量,作用域为从定义位置开始到本源文件结束文件结束N 变量从作用域可分为外部变量和内部变量,变量从作用域可分为外部变量和内部变量,即全局变量和局部变量即全局变量和局部变量N 变量从生存期的角度看可分为静态变量和变量从生存期的角度看可分为静态变量和动态变量动态变量N 函数也有内部函数与外部函数,访问时有函数也有内部函数与外部函数,访问时有所不同所不同教学内容教学内容函数函数教学目标教学目标应知应知了解模块化程序的结构了解模块化程序的结构掌握函数的定义方法掌握函数的定义方法掌握函数的调用和参数传递掌握函数的调用和参数传递重点重点函数的定义和调用函数的定义和调用形参和实参形参和实参难点难点形参与实参的意义、作用与区别形参与实参的意义、作用与区别参数的两种传递方式参数的两种传递方式全局变量和局部变量的作用全局变量和局部变量的作用例例例例6 6 对例对例对例对例4 4改进,定义一个整型数组改进,定义一个整型数组改进,定义一个整型数组改进,定义一个整型数组a10a10,要求在,要求在,要求在,要求在一个函数中以一个函数中以一个函数中以一个函数中以数组元素作实参数组元素作实参数组元素作实参数组元素作实参将将将将a a数组中各个元素的数组中各个元素的数组中各个元素的数组中各个元素的值加值加值加值加2 2。int a10;int a10;给数组给数组给数组给数组a a赋初值赋初值赋初值赋初值add2(ai)add2(ai)i=0 to 9i=0 to 9outputoutput数组数组数组数组a areturn n+2;return n+2;add2(int n)add2(int n)#include #include void main()void main() int add2(int);int add2(int);int a10,i;int a10,i;printf(Please input array a:n);printf(Please input array a:n);for(i=0;i10;i+)for(i=0;i10;i+) printf(a%d=,i);printf(a%d=,i); scanf(%d,&ai); scanf(%d,&ai); for(i=0;i10;i+)for(i=0;i10;i+)ai=add2(ai);ai=add2(ai);printf(printf(加加加加2 2以后的数组为以后的数组为以后的数组为以后的数组为:n);:n);for(i=0;i10;i+)for(i=0;ib),m=0(ab),m=0(ab),k=0(a=b)for i=0 to 10for i=0 to biaibiaibiaibiT TT TF FF Fn+n+m+m+k+k+输出输出输出输出n/m/kn/m/k#include #include void main()void main() int a10,b10,i,n=0,m=0,k=0;int a10,b10,i,n=0,m=0,k=0;printf(enter array a:n);printf(enter array a:n);for(i=0;i10;i+)for(i=0;i10;i+) printf(a%d=,i);printf(a%d=,i); scanf(%d,&ai); scanf(%d,&ai); printf(“nenter array b:n);printf(“nenter array b:n);for(i=0;i10;i+)for(i=0;i10;i+) printf(b%d=,i);printf(b%d=,i);scanf(%d,&bi);scanf(%d,&bi); printf(n);printf(n);for(i=0;i10;i+)for(i=0;ibi)if(aibi)n+;n+;else if(aibi)else if(aibi %d timesnai=bi %d printf(aibi %d timesnai=bi %d timesnaibi %d timesn,n,m,k);timesnaik)if(nk)printf(array a is larger than array printf(array a is larger than array bn);bn);else if(nk)else if(nb),m=0(ab),m=0(ab),k=0(a=b)for i=0 to 10for i=0 to biaibiaibiaiy) flag=1; if(xy) flag=1; else if(xy) flag=-1; else if(xy) flag=-1; else flag=0; else flag=0; return (flag); return (flag); for(i=0;i10;i+)for(i=0;i10;i+)if(if(large(ai,bi)=1large(ai,bi)=1) )n+;n+;else if(else if(large(ai,bi)=0large(ai,bi)=0) )m+;m+;elseelsek+;k+;#include #include void main()void main() int a=2,b=1;int a=2,b=1;printf(nn);printf(nn); int c;int c;c=a+b;c=a+b; printf(c=%dn,c);printf(c=%dn,c); 递归是一个递归是一个过程直接调用自己过程直接调用自己或通过一系列的过程调用或通过一系列的过程调用间间接地调用自己接地调用自己的过程。递归的能力在于用的过程。递归的能力在于用有限的语句来定有限的语句来定义对象的无限集合义对象的无限集合。 1.边界条件边界条件2.递归前进段递归前进段3.递归返回段。递归返回段。4.当边界条件不满足时,递归前进当边界条件不满足时,递归前进;当边界条件满足时,当边界条件满足时,递归返回。递归返回。 迭代是直接进行计算或处理的过程。迭代是直接进行计算或处理的过程。1.确定迭代变量确定迭代变量2.建立迭代关系式建立迭代关系式3. 对迭代过程进行控制对迭代过程进行控制 例子:编写一个程序,输入一个字符串,统计其中各个字符出例子:编写一个程序,输入一个字符串,统计其中各个字符出例子:编写一个程序,输入一个字符串,统计其中各个字符出例子:编写一个程序,输入一个字符串,统计其中各个字符出现的频度。现的频度。现的频度。现的频度。char str100,a100; int c100;char str100,a100; int c100;gets(str);gets(str);k=fun(str,a,c);k=fun(str,a,c);i=0 to k-1i=0 to k-1output cioutput cii=0 to k-1i=0 to k-1output aioutput aij+;j+;len=strlen(str); k=0;a0=str0;c0=1len=strlen(str); k=0;a0=str0;c0=1i=0 to len-1i=0 to len-1ci=0;ci=0;i=1 to len-1i=1 to len-1jk&aj!=strijk&aj!=strij=0;j=0;j=kj=kak=stri;ck+;k+ak=stri;ck+;k+; ;cj+;cj+;return k;return k;T TF Fint fun(char str,char a,int c)int fun(char str,char a,int c) /返回返回返回返回strstr中不同字符的个数中不同字符的个数中不同字符的个数中不同字符的个数 int i,j,k=0,len=strlen(str); int i,j,k=0,len=strlen(str); /len/len为为为为strstr的长度的长度的长度的长度a0=str0; a0=str0; c0=1;c0=1;k+;k+;for(i=1;ilen;i+)for(i=1;ilen;i+)ci=0;ci=0;for(i=1;ilen;i+) for(i=1;ilen;i+) /扫描扫描扫描扫描strstr中所有字符中所有字符中所有字符中所有字符 j=0;j=0;while(jk&aj!=stri) while(jk&aj!=stri) /检查检查检查检查stristri是否已在是否已在是否已在是否已在aa中中中中j+;j+;if(j=k) if(j=k) /stri/stri未检查过未检查过未检查过未检查过 ak=stri;ak=stri; ck+;ck+;k+;k+; else else /stri/stri已检查过已检查过已检查过已检查过cj+;cj+; return k;return k; #include #include #define Max 100#include #include #define Max 100void main()void main() char strMax,aMax;char strMax,aMax;int cMax,k,i;int cMax,k,i;printf(input string:);printf(input string:);gets(str);gets(str);k=fun(str,a,c);k=fun(str,a,c);printf(printf(统计结果如下统计结果如下统计结果如下统计结果如下:n);:n);printf( printf( 字符字符字符字符 ); );for(i=0;ik;i+)for(i=0;ik;i+)printf(%3c,ai);printf(%3c,ai);printf(n);printf(n);printf( printf( 频度频度频度频度 ); );for(i=0;ik;i+)for(i=0;ihigh)if(lowhigh)return -1;return -1;if(valuemid=key)if(valuemid=key)return mid;return mid;else if(keyvaluemid)else if(keyvaluemid)return return search(value,key,low,mid-1);search(value,key,low,mid-1);elseelsereturn return search(value,key,mid+1,high);search(value,key,mid+1,high);search(value,key,low,highsearch(value,key,low,high) )lowhighlowhighreturn -1return -1T TF Fmid=(low+high)/2mid=(low+high)/2key=valuemidkey=valuemidreturn midreturn midT TF FkeyvaluemidkeyvaluemidF FT Tsearch(value,key,low,mid-1)search(value,key,low,mid-1)search(value,key,mid+1,high)search(value,key,mid+1,high)void input(int value)void input(int value) int i;int i;printf(value0=);printf(value0=);scanf(%d,&value0);scanf(%d,&value0);for(i=1;iNUM;i+)for(i=1;iNUM;i+) printf(value%d=,i);printf(value%d=,i);scanf(%d,&valuei);scanf(%d,&valuei);while(valueivaluei-1)while(valueivaluei-1) printf(reinput value%d=,i);printf(reinput value%d=,i);scanf(%d,&valuei);scanf(%d,&valuei); void output(int value)void output(int value) int i;int i;for(i=0;iNUM;i+)for(i=0;ihigh)if(lowhigh)return -1;return -1;mid=(low+high)/2;mid=(low+high)/2;if(valuemid=key)if(valuemid=key)return mid;return mid;else if(keyvaluemid)else if(keyvaluemid)return search(value,key,low,mid-1);return search(value,key,low,mid-1);elseelsereturn search(value,key,mid+1,high);return search(value,key,mid+1,high); #include #define NUM 10#include #define NUM 10void main()void main() int valueNUM,result,key;int valueNUM,result,key;printf(Please input array value:n);printf(Please input array value:n);input(value);input(value);printf(array value:n);printf(array value:n); output(value);output(value);printf(nEnter a key:);printf(nEnter a key:);scanf(%d,&key);scanf(%d,&key);result=search(value,key,0,NUM-1);result=search(value,key,0,NUM-1);if(result!=-1)if(result!=-1)printf(The %d is the %dth printf(The %d is the %dth elementn,key,result);elementn,key,result);elseelseprintf(Fail to find %dn,key);printf(Fail to find %dn,key);
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号