c语言看不懂形参实参以及调用方法的必看,C语言看不懂形参实参以及调用方法的必看.ppt...

253b171540df25e1b84436cbe50dfc72.gifC语言看不懂形参实参以及调用方法的必看.ppt

第8章 函数,主要内容 1、函数的定义 2、函数的调用(包括嵌套调用和递归调用) 4、局部变量和全局变量 5、变量的存储类别 重点 1如何定义函数(即如何编写函数) 2如何调用函数(包括库函数和自定义函数),函数的引入,函数函数是完成某些特定功能的代码块。 使用函数的优点 1)实现模块化设计将一个大任务分解成一个个的小任务,然后每个任务分别用函数实现。 2)实现“编写一次,多次调用”,避免在不同的程序中重复编写相同的函数。 3)便于程序调试和维护,因为每个函数之间是相互独立的。 函数的分类库函数和用户自定义函数,8.1 函数的定义,例8. 1编写函数max求两个整数x和y中的较大数。 int max int x, int y /*函数头*/ int zx; /*函数体*/ if xy zy; return z; main int a, b, d; printf“ a and b“; scanf“d d“, 例8.2设某程序中需多次用到打印表头(如下所示)的功能,该功能用函数实现 void line printf“n “; printf“n* score list *“; printf“n “; 本例中,函数的类型 void,函数名为line,函数无参数。 该函数无返回值,所以函数类型为void型。函数定义的一般形式如下 函数类型 函数名类型名 形式参数1,类型名 形式参数2, 说明部分 语句部分 1.函数名是该函数的唯一标识符,一般函数的命名最好做到“见名知义”。 2.函数类型函数的返回值的类型。 当函数无返回值时,规定其类型为 void。 当函数返回值为 int 时,函数类型可以省略。3. 形式参数形参是函数被调用时用于接收实参值的变量。 根据实际需要可有可无。没有形参时,圆括号也不可省;多个参数之间应用逗号分隔。参数包括参数名和参数类型。 形参的类型说明可有如下两种格式 int maxint a,int b /*形参的类型在形参表中直接说明*/ return abab; 或 int maxa,b int a,b; /*形参的类型在函数体前、函数名后说明*/ returnabab; 前者为标准格式,后者为传统格式,通常用前者。4.函数体即函数功能的具体实现。 它包括两部分 说明部分和执行部分,其中说明部分包括函数中所用的局部变量等的说明、函数中要调用的函数的说明。 注意 函数不能嵌套定义,即函数内不能再定义函数,这样可以保证函数间是相互独立的,以实现模块化程序设计。 5.空函数 函数类型 函数名 调用此函数时,什么也不做。只是表明这里要 调用一个函数,而现在这个函数的功能还没实现。空函数在程 序设计中常常用到的 1)预留函数,便于以后扩充程序功能。 2)便于程序的模块化设计和调试程序设计中往往根据需要确定若干模块,分别由一些函数来实现。一个大系统,需要编写很多用户函数,而这些函数不可能 也没有必要同步完成,通常足从一些基本模块开始,编写一个调试一个,对于没有编写 的函数就需要用空函数代替。从而也有利于集体创作。,空函数举例,例8.3 编写小学生算术练习系统的主程序 显示主菜单,用户选择,根据选择执行加、减、乘、除、退出5项功能之一。 重复上述步骤,直至选择退出。 其中主程序调用的函数有显示主菜单函数list_menu,加、减、乘、除、退出函数分别是add, sub, mul,divide, end. 以上函数除list_menu外此时均为空函数。 程序l8_1_4.cinclude “stdio.h“ /*l8_1_4.c*/ main void add,sub,mul,divide,end,list_menu; int n; do list_menu; scanf“d“, void list_menu printf“n the rcise system for primitive students*“; printf“n 1. add “; printf“n 2. sub “; printf“n 3. mul “; printf“n 4. divide*“; printf“n 5. end n“; void add void sub void mul void divide void end ,问题如何定义一个函数,第一步分析函数需要的参数,包括参数的的个数以及每个参数的类型, 第二步 分析函数返回值的类型,若无返回值,则为 void。 函数的返回值可看作是函数执行完后需输出的一个数据。 第三步编写函数体 说明 参数和返回值是函数之间的接口,即函数之间通过参数和返回值进行通信。参数包括执行该函数时需要的数据信息,以及返回数据的有关信息。例如 1)求n 要处理的数据是n,因此必须有一个参数n,类型为 int。返回值为long 型。即 long fact int n 2)打印表头 不需输入任何数据即可执行该函数,因此无参数。执行该函数无返回值,因此函数类型为 void。即 void line 3)求两个整数m和n的最小公倍数,执行该功能时必须有两个整型参数,返回值为整型。程序l8_1_5.c int min_multipleint m, int n (见下页) 4)求一批整型数据(n个)中的最大值。实现该功能的函数的参数有两个该批数据的首地址及数据的个数。返回值为一个整型数。 int max int data , int n /*例3 计算两个整数的最小公倍数 l8_1_5.c*/ main int m, n , min; int min_multiple int, int ; /*函数声明*/ printf“n m,n“; scanf“dd“, ,8.2 函数的调用,重点 1、对被调函数的声明 2、如何调用一个函数 3、主调函数和被调函数之间如何进行数据传递 例8.5 调用函数fact 求nn由用户输入)。 分三种情况 1函数fact与主函数在同一文件中,且main 在fact前面。 2函数fact与主函数在同一文件中,且main在fact之后。 3函数fact与main不再同一程序文件中。main /*1 main 在fact前面 */ int n; long p; long factint; /*函数声明*/ scanf“d“, /*函数返回*/ 结论被调函数在后,需在主调函数中先声明后调用。/* 2主调函数在被调函数之后*/ long fact int m /* 函数定义*/ int i; long s1; fori1;im;i s*i; returns; main int n; long p; /*不需函数声明*/ scanf“d“, 结论被调函数先于主调函数被编译,因此在编译主调函数时已知被调函数的类型等信息。故不需函数声明。/*3设fact函数存放在文件f1.c中,则编写主调函数时需用include 命令对被调函数声明*/ include main int n; long p; scanf“d“, 结论该程序的效果与(2)相同,由此可实现将多个文件连接成一个程序。 同理,对库函数的调用都要在main函数前用include命令将函数所在的头文件包含进来。,函数声明小结,被调函数必须是已存在的函数,通过“函数声明”告知编译系统关于被调函数的有关信息。 函数声明的形式函数类型 函数名(参数表); (注意与函数定义的区别) 1、若被调函数是库函数或用户已编写的函数(与主调函数不在同一文件中),则使用前需在程序的开头用include命令将被调函数的信息包含进来。 2、若主调函数与被调函数在同一文件内,且主调函数在前,则必须在主调函数的说明部分或主调函数的前面对被调函数进行说明。 3、以下情况下可以省略对被调函数的说明。 a函数类型为整型 b被调函数在主调函数之前定义 通常,将所有函数的说明集中在程序开头;或将所有函数的信息写入一个文件,编程时用include 命令将其包含进来即可。,函数的调用与返回过程小结,1、函数调用的一般形式 函数名实参表 如 pfactn; printf“d”,power2,n;等 注意实参与形参的类型、个数、顺序必须一致。 2、调用过程 1)在调用函数时,首先将实参的值赋给形参;再将控制流程转到被调函数; 2)然后执行被调函数。 3)当被调函数执 行到return语句,或执行到被调函数函数体最后的一个大花括号时,控制流程返回到 主调函数的断点处继续执行主调函数。如果被调函数有返回值,则控制流程返回的同时将该返回值带回主调函数。,3、函数的返回,函数返回的实现 1)函数体中通过执行return语句返回,其格式有3种return expression); 或 return expression ; 或return; 2若函数体中无return语句,当执行到函数末尾时自动返回到调用函数。 注意 1函数的返回值最多只有一个,可通过return 语句返回主调函数。 2当有多个值需要返回主调函数时,用return语句无法实现,只能通过传地址调用实现。如对数组元素排序等。,4. 参数传递实参与形参的结合,形参定义函数时的参数为形参,此时的参数无具体的值,仅仅表示参数的类型、个数、以及在函数体内对其如何处理。 其作用是该函数被调用时用来接收实参的值. 实参;调用函数时的参数为实参,它表示该函数要处理的数据的信息,因此实参必须有确定的值。调用时,将实参的值传给形参。 要求调用函数时,实参与形参的类型、个数必须完全一致。 分析例8.4程序的调用过程明确实参与形参的作用。(传值调用单向传递)例8. 4以下程序企图通过调用swap函数,交换主函数中变量x和y中的数据。请观察程序的输出结果。 void swapint a, int b int t; printf“2ad bdn“, a, b; ta;ab;bt; printf“3ad bdn“, a, b; main int x10,y20; printf“1xd ydn“, x, y; swapx, y; printf“4xd ydn“, x, y; 程序运行结果如下 1x10 y20 2a10 b20 3a20 b10 4x10 y20 结论参数的传递是单 向的,即只能由实参传 给形参,在被调函数中 对形参的改变的不影响 实参的值。例8.12 编写函数实现用选择法对n个整数排序。编写主函数实现数据的输入输出。 分析 主程序的算法 S1输入一批数据个数为N,存入一维数组aa。 S2调用函数sort,对一维数组中的数据按从小到大的顺序排序。 S3输出数组aa中的各元素。 函数sort的编写 首先,确定函数的类型void; 参数一维数组的首地址,数据的个数,共2个; 然后编写函数体,实现排序。 重点分析参数的传递,比较传值与传地址的区别,各有何用处 (图示形参数组与实参数组的结合方式)/*主函数*/ define N 10 main int aaN, i; void sortint b ,int n; printf“n enter integers for sort;“; fori0;iN;i scanf“d“, ,/*函数sort*/ void sortint b ,int n int i,j,t,k; fori1;in-1;i k0; forj1;jn-i;j ifbkbj kj; tbk;bkbn-i; bn-it; /*循环体排一遍*/ 数组aa与数组b实际上是一个数组。b 的长度无意义,因此可以不说明。,例8.12 运行结果与图示 enter 5 integers1 2 5 7 3 after sort 7 5 3 2 1,比较两种参数传递方式,传值调用单向数据传递,对形参的改变不影响实参的值,且只能通过return语句返回最多一个值 例8.4 传地址调用实参传给形参的是数据的地址,所达到的目的是形参与实参共用同一片存储单元,对形参的改变实际上是对实参的改变,从而实现主、被调函数之间的多个数据传递。例8.12,5. 函数的嵌套调用,例8. 6 嵌套调用实例. fint x int t; txx; returnt; g int a,int b int z; zfa*b; returnz; 函数类型省略,默认为整型。,main int x12,x25,y; ygx1,x2; printf“d“,y; 被调函数在前,不需函数声明。 调用过程 在main函数中调用g,执行g函数的的过程中调用 f;执行完f函数后返回到g接着执行,执行完g后返回到main.(图示),例8. 7 编写函数,验证陈景润研究的哥德巴赫猜想任意大偶数为两个素数之和并输出这两个素数(所谓大偶数是指6开始的偶数)。 分析 isprimeint a实现判断一个数a是否为素数;evenint x实现找到并输出两个素数(其和等于x);main实现输入一个大偶数,并调用even输出该大偶数对应的两个素数。 设变量x为任意大偶数,可从x中依次减去i,i从2变化到x/2;依次判断i、x-I是否为素数。步骤如下 i初值为2。 判断i是否是素数。若是,执行步骤;若不是,执行步骤。 判断x-i是否是素数。若是,执行步骤;若不是,执行步骤。 输出结果,返回调用函数。 使i增1。 重复执行步骤。/*例8.7程序*/ include “math.h“ int isprime int; /*函数声明*/ void evenint; main int a; printf“Enter a even number6“; scanf“d“, void evenint x /*函数定义*/ int i; fori2;ix/2;i ifisprimei ifisprimex-i printf“dddn“,x,i,x-i; return ; int isprimeint a /*函数定义*/ int i, k sqrta; fori2; ik; i if ai0 return 0; return 1; ,8.4递归调用,递归一个函数直接或间接的调用自己。 分析递归问题的关键 1)每次调用自己时参数的变化规律。 2)递归结束的条件。 例8.8 求n. 分析fnfn-1*n n1规律 f11 n1-递归结束条件 程序l8_4_1.c 分析程序的执行过程,理解递归中的“递进”与“回推”。main /*程序L8_4_1.c*/ int n; long p; long fint; /*对被调函数的声明*/ printf“n n“; scanf“d“, /*函数的返回*/ 类似的递归问题 1。猴子吃桃 int peach int day int n; ifd10 n1; else n2*peachday11; return n; 2。猜年龄第一个人说它比第二个人大4岁,第二个人说它比第三个人大4岁,第三个人说它比第四个人大四岁,第四个人10岁,问第一个人多大,8.5 局部变量和全局变量,指变量的作用范围不同。 局部变量 在函数体内定义的变量。 作用范围只在本函数内有效 如前面例题中的变量、数组等。 全局变量 在函数体外定义的变量 作用范围从定义该变量的位置开始,到本源程序文件结束。程序 /*全局变量x, y*/ int x100; float y66.6; f1 float y0; /*局部变量 y*/ printf“xdt”,x; printf“yft”,y; int z1; f2 int i; /*局部变量 i*/ fori1;i5;i putchar*; printf“n zdt “,z; /*全局变量 z 从 定义起至程序末起作用*/,main f1; f2; printf“yfn”,y; /*输出全局变量y*/ 运行结果 x100 y0.000000 z1 y66.600000 /*全局变量x,y在本程序内起作用*/ /*局部变量y的作用范围内,全局变量y不作用*/,int d1; /*全局变量d*/ funint p int d5; /*局部变量d*/ dp; /*使用局部变量d*/ printf“d“,d; main int a3; funa; da; /*使用全局变量d*/ printf“d“,d; 运行结果84 结论在同一源程序文件中,若外部变量与局部变量同名,则在局部变量的作用范围内,外部变量不起作用。,局部变量和全局变量小结,局部变量保证了函数之间的独立性。(常用) 全局变量增加了函数之间数据传递的通道,但降低了函数间的独立性,降低了程序的清晰性,因此副作用太大。除非特别需要时,一般不用。 占用内存情况 局部变量仅当他所在的函数被调用时才存在,执行完该函数返回后,该变量不再存在 全局变量在程序的全部执行过程中一直存在,直至程序执行完,才释放它所占的内存空间,8.6 变量的存储类别,变量和函数均有两个属性 数据类型和存储类别 存储类别指数据在内存中的存储方式。根据变量的“生存期”不同,变量的存储类别包含以下四种 自动的 auto 静态的 static 寄存器的 register 外部的 extern,自动的(auto)变量,函数的形参和在函数中定义的变量(通常省略存储类别,)即隐含指定为自动变量。前面17章中的变量均属自动变量。 自动变量在需要时系统给他门分配存储空间,在函数调用结束时自动释放这些存储空间。 例auto int a2,b3; 与int a2,b3;等价。,静态的(static),1、静态局部变量 作用域为本函数内部 存储类别为静态存储类,因此其生存期与该函数所在程序运行期间相同。即当函数调用结束时能保留原值,在下一次调用该函数时该变量的值是上一次函数调用结束时的值,直至程序运行结束 例next pagefuncint a,int b /*例8.6.1*/ static int m0,i2;/*静态局部变量m,I*/ im1; miab; returnm; main int k4,m1,p; /*局部变量k,m,p*/ pfunck,m; printf“5d“,p; pfunck,m; printf“5dn“,p; 运行结果 8 17 /*图示执行过程中变量的存储空间占用及值的变化情况*/int d1; /*全局变量d*/ /*例8.6.2*/ funint p static int d5; /*静态局部变量d*/ dp; printf“5d“,d; returnd; main int a3; /*自动变量 a*/ printf“5dn“,funafund; 运行结果 6 15 15,Register 变量,register int k; 则给变量k分配的空间为某个寄存器。 优点速度快。 只有局部变量和形参可以定义为register变量。因为机器的寄存器数量有限,因此该类型不常用。,外部的(extern)变量,用extern声明外部变量,是为了扩展外部变量的作用域。 因外部变量不常用,因此extern也很少使用。 必须使用外部变量时,一般建议使用静态全局变量。即在函数体外定义变量时存储类别为static 如 static int a2; f 变量 a的作用范围仅限于本源程序文件内。其它程序中即使用extern int a;声明也不能引用a。,8.7内部函数与外部函数,外部函数如不加特别说明,函数都是全局的,即外部的,一个函数可以调用另一文件中的函数。(项目文件的使用 内部函数存储类别为static,该函数仅限于本程序文件使用,其它程序不能调用之。,综合题1,编程实现小学生算术练习系统主菜单包括5项(加法、减法、乘法、除法、退出),前四项中每一项又包括子菜单(一级、二级、三级、返回4项),其中一级实现10以内的运算,二级实现50以内的整数运算,三级实现100以内的整数运算;进入某一级后,反复练习(由机器产生两个随机数,用户输入运算结果,输出正确或错误)待结束时给出本级题目中计算正确的百分比。 要求每个功能分别用函数实现。程序l8_t.c,综合题2,自动阅卷程序设单选题20个(2分/题),多选题20个(每题4个供选答案,3分/题,且只要与答案不一致即错)。编写函数实现阅单选题,阅多选题,阅一个人的答题;编写主函数实现批阅N个人的答题卡(正确答案在主程序中输入)。 分析 Main 1输入正确答案,分别存入一维数组dd,二维数组ss; 2 批阅N个人的答题(用循环),将成绩存入数组sc。3)输出每个人的最后成绩。 Person 函数类型为int; 参数两个dd,ss; 函数体1)输入某人的答案,分别存入dd1和ss1,2)分别调用函数single和many判别对错并计分,返回总成绩。Single函数类型int ,参数dd,dd1; 函数体统计数组dd与dd1中相同元素的个数,乘2即得单选题的成绩,返回该成绩。 Many函数类型int ,参数ss,ss1; 函数体统计数组ss与数组ss1中对应行元素相同的行数,乘3即得多选题的成绩,并返回。 然后分析各函数的具体实现算法。 程序1l8_3_2.c 分析程序中的传地址调用,嵌套调用时程序的执行过程。 程序2l8_3_2_q.c 定义存放正确答案的数组为全局的,则dd,ss将不作为参数使用。(一般情况使用参数传递)include “stdio.h“ /*程序1*/ define N 400 /*num of person*/ define NUM 20 /*num of question*/ main char ddNUM1,ssNUM15; int scN1,i; printf“n enter right answer of single selectn“; printf“natpress enter after finished ing all of answers.n“; fori1;iNUM;i ddigetchar; getchar;printf“n enter answer of multi selectn“; printf“natpress enter after ing a questionn“; fori1;iNUM;i getsssi; fori1;iN;i scipersondd,ss; printf“n no score “; fori1;iN;i printf“n -6d-6d“,i,sci; int personchar dd,char ss5 char dd121,ss1315; int s,i; int signle,many; printf“n enter answer of single select“; fori1;iNUM;i dd1igetchar; getchar; printf“n enter answer of multi select“; fori1;iNUM;i getsss1i; ssingledd,dd1manyss,ss1; returns; int singlechar dd ,char dd1 int n0,i; fori1;iNUM;i ifddidd1i n; return2*n; int manychar ss 5,char ss1 5 int n0,i; fori1;iNUM;i ifstrcmpssi,ss1i n; returnn*3; ,多个文件组成一个程序的方法,1、使用project生成项目文件 见ch16.8 2、使用include 将所有的文件包含到一个文件中。例8.5 3,作业,8.1、 8.2、8.3、8.4、8.10,练习,1、求一元二次方程的根.要求a,b,c由主函数输入,用3个函数分别求b2-4ac的值大于0、等于0、小于0时方程的根并输出。 分析 主函数 1输入a,b,c 2计算 d b2 - 4ac ,然后根据d的值大于0、等于0、小于0分别调用三个函数f1 f2 f3 分析各个函数的实现 函数类型 函数名(形参及类型) 程序x8_1.c 常见错误),练习,例8.2程序x8_2.c main void addfloat,float ; float a,b; scanf“ff“, ,问题 若将函数add的类型改为float,则运行时出错 4 6CR 10.000000float point errordomain 若改为float后在add函数体末加returns; 则结果正确。 若将add声明中的参数去掉,则实参并未传给形参。 若参数为整型,则函数声明时参数类型可可省略。,递归调用练习,x8.9 分析 函数类型float 函数名pp 参数2个 n整型 ,x实型 函数体根据n的值决定采用3个公式中的一个计算函数值。 (用选择结构) 当n1时,计算函数值的过程中又调用函数pp,即递归调用。参数的变化规律为 n-1, n-2 。即ifn1 h2*x*ppn-1,x-2*n-1*ppn-2,x 递归结束的条件为n等于0或n等于1 程序x8_13.c,通过参数在函数间传递数据,X8.14 分析 主函数调用4个函数,设函数名分别为average1, average2, max_sc, jun. 参数分别为 void average1float s5,float a void averagefloat s5 void max_scfloat s5 void junfloat a 分别实现的功能为,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值