实验5函数 5.1函数的定义及调用 【实验目的】 1.掌握函数的定义、声明和调用: 2.掌握函数的实参、形参和返回值的概念及使用。 【相关知识点】 1.函数定义的一般形式 函数定义的一般形式为: 函数类型函数名(形参表) 函数实现过程: 示例1: void print message()/体函数首部*/ /体以下是函数体*/ { printf("Hello Word!\n"); } 示例2: int max(intx,inty)/体函数首部*/ /体以下是函数体*/ int Z; z=x>y?x:y; return z; -80-
实验 5 函数 5.1 函数的定义及调用 【实验目的】 1. 掌握函数的定义、声明和调用; 2. 掌握函数的实参、形参和返回值的概念及使用。 【相关知识点】 1. 函数定义的一般形式 函数定义的一般形式为: 函数类型 函数名(形参表) { 函数实现过程; } 示例 1: void print_message( ) /* 函数首部 */ /* 以下是函数体 */ { printf(“Hello Word!\n”); } 示例 2: int max(int x,int y) /* 函数首部 */ /* 以下是函数体 */ { int z; z=x>y?x:y; return z; - 80 -
} 函数定义值得注意的问题如下: (1)函数的定义包括函数首部和函数体两部分,其中函数首部由函数类型、函数名和形 参表组成,函数体包含一对大括号内的若干条语句,体现函数的实现过程: (2)在函数首部,函数类型指函数返回值的类型,一般与return语句中表达式的类型一 致,return语句中的表达式反映了函数运算的结果,通过return语句结束该函数的运行并将该 结果回送给主调函数,但rtum语句只能返回一个值:如果函数不返回任何值,应当将函数类 型定义为“void”,函数体中可以出现return语句,也可以省略:如果在定义函数时不指定函 数类型,系统会隐含指定函数类型为int型: (3)从函数的形式看,函数分为有参函数和无参函数:主调函数在调用被调函数时,通 过参数向被调函数传递数据,形参表中各个形参之间用逗号分隔,每个形参前面的类型必须 分别写明,此函数为有参函数,如示例2:主调函数不向被调函数传递数据,此函数为无参函 数,如示例1。 2.函数声明的一般形式 函数声明的一般形式为: 函数类型函数名(形参表): 即只写函数定义的第一行(函数首部),并以分号结束。 示例: #include void main(void) int a,b,c; int max(int x,int y),/体函数声明*/ printf("请输入两个整数,中间用逗号分隔:"); scanf("%d,%d"&a,&b); c-max(a,b); printf"max=%dn",c方 } int max(int x,int y) -81-
} 函数定义值得注意的问题如下: (1)函数的定义包括函数首部和函数体两部分,其中函数首部由函数类型、函数名和形 参表组成,函数体包含一对大括号内的若干条语句,体现函数的实现过程; (2)在函数首部,函数类型指函数返回值的类型,一般与 return 语句中表达式的类型一 致,return 语句中的表达式反映了函数运算的结果,通过 return 语句结束该函数的运行并将该 结果回送给主调函数,但 return 语句只能返回一个值;如果函数不返回任何值,应当将函数类 型定义为“void”,函数体中可以出现 return 语句,也可以省略;如果在定义函数时不指定函 数类型,系统会隐含指定函数类型为 int 型; (3)从函数的形式看,函数分为有参函数和无参函数;主调函数在调用被调函数时,通 过参数向被调函数传递数据,形参表中各个形参之间用逗号分隔,每个形参前面的类型必须 分别写明,此函数为有参函数,如示例 2;主调函数不向被调函数传递数据,此函数为无参函 数,如示例 1。 2. 函数声明的一般形式 函数声明的一般形式为: 函数类型 函数名(形参表); 即只写函数定义的第一行(函数首部),并以分号结束。 示例: #include void main(void) { int a,b,c; int max(int x,int y); /* 函数声明 */ printf("请输入两个整数,中间用逗号分隔:"); scanf("%d,%d",&a,&b); c=max(a,b); printf("max=%d\n",c); } int max(int x,int y) - 81 -
intZ z=x>y?x:y; return Z; } 函数声明值得注意的问题如下: (1)函数声明的目的主要是说明函数的类型和参数的情况,以保证程序编译时能判断对 该函数的调用是否正确: (2)如果自定义函数被放在主调函数的后面,则需要在函数调用前,加上函数声明: 如果自定义函数被放在主调函数的前面,则不需要写函数声明。 3.函数调用的一般形式 函数调用的一般形式为: 函数名(实参表) 实参可以是常量、变量和表达式。 示例: #include0) y=1; -82-
{ int z; z=x>y?x:y; return z; } 函数声明值得注意的问题如下: (1)函数声明的目的主要是说明函数的类型和参数的情况,以保证程序编译时能判断对 该函数的调用是否正确; (2)如果自定义函数被放在主调函数的后面,则需要在函数调用前,加上函数声明; 如果自定义函数被放在主调函数的前面,则不需要写函数声明。 3. 函数调用的一般形式 函数调用的一般形式为: 函数名(实参表) 实参可以是常量、变量和表达式。 示例: #include void main(void) { int f (int x); int a,b; scanf("%d",&a); b=f(a); /* 函数调用 */ printf("b=%d\n",b); } int f(int x) { float y; if (x>0) y=1; - 82 -
if(x--0) y=0: if(x<0) y=l1; return y; 函数调用值得注意的问题如下: (I)函数调用的过程:用以上示例来说明,计算机在执行程序时,从主函数main()开始 执行,当程序运行到语句 b=f(a); 时,主函数main()被暂停执行,此时调用f()函数,将实参a的值传递给形参x,并执行 f)函数中的语句,执行到最后一条语句 return y; 时,函数调用结束,并将函数的返回值y返回到main()函数中调用处,此时从先前发生 函数调用的位置继续执行,将返回值赋值给变量b: (2)形参和实参的定义:定义函数时函数名后面括号中的变量名,称为形参,在以上示 例中,变量x是形参:调用函数时函数名后面括号中的表达式,称为实参,在以上示例中, 是实参:形参必须是变量,而实参可以是变量、常量或者表达式:形参和实参必须一一对应, 要求数量相同,类型一致: (3)参数传递:在程序运行中,遇到函数调用时,将实参的值依次传递给形参,这就是 参数传递:参数传递有值传递和地址传递两种,以上示例是属于值传递,即在参数传递过程 中,将实参的值复制给形参,这种参数传递是单向的,只允许实参把值复制给形参,而形参 的值即使在函数中改变了,也不会影响实参:函数调用时,将数据的存储地址作为参数传递 给形参,这就是地址传递,这种参数传递是双向的,函数调用能改变主调函数中变量的值, 地址传递主要在指针环节有进一步的讲解。 【实验任务】 一、程序改错 该部分实验主要训练学生读简单程序的能力,并在理解程序的基础上,改正程序中出现 -83-
if (x==0) y=0; if (x<0) y=-1; return y; } 函数调用值得注意的问题如下: (1)函数调用的过程:用以上示例来说明,计算机在执行程序时,从主函数 main( )开始 执行,当程序运行到语句 b=f(a); 时,主函数 main( )被暂停执行,此时调用 f( )函数,将实参 a 的值传递给形参 x,并执行 f( )函数中的语句,执行到最后一条语句 return y; 时,函数调用结束,并将函数的返回值 y 返回到 main( )函数中调用处,此时从先前发生 函数调用的位置继续执行,将返回值赋值给变量 b; (2)形参和实参的定义:定义函数时函数名后面括号中的变量名,称为形参,在以上示 例中,变量 x 是形参;调用函数时函数名后面括号中的表达式,称为实参,在以上示例中,a 是实参;形参必须是变量,而实参可以是变量、常量或者表达式;形参和实参必须一一对应, 要求数量相同,类型一致; (3)参数传递:在程序运行中,遇到函数调用时,将实参的值依次传递给形参,这就是 参数传递;参数传递有值传递和地址传递两种,以上示例是属于值传递,即在参数传递过程 中,将实参的值复制给形参,这种参数传递是单向的,只允许实参把值复制给形参,而形参 的值即使在函数中改变了,也不会影响实参;函数调用时,将数据的存储地址作为参数传递 给形参,这就是地址传递,这种参数传递是双向的,函数调用能改变主调函数中变量的值, 地址传递主要在指针环节有进一步的讲解。 【实验任务】 一、程序改错 该部分实验主要训练学生读简单程序的能力,并在理解程序的基础上,改正程序中出现 - 83 -
的问题,这些问题都是初学者经常容易犯的错误,针对函数的定义及调用这一节,主要有如 下问题: 1)当使用用户自定义函数时,若该函数的位置在主调函数的后面,在主调函数中没有 对被调函数做声明: 2)函数类型和函数的返回值类型不一致。 针对上面的问题,查找下面程序中存在的问题,并改正调试。 1.打开c:lc-programming5pg510l.cpp,该程序是求两个数的和,有一个小问题,请修改, 使程序能正确运行。修改后的程序以pg5101ok.cpp保存。该源程序内容如下: #include void main(void) float a,b,c; printf("请输入两个数,中间用逗号隔开:"); scanf("%f,%f",&a,&b); c=add(a,b); printf("两个数之和为:%fn",c方 } float add(float x,float y) float z; Z-X+y; return z; } 了提示:如何发现问题? 编译该程序,系统报告两个编译出错信息,如图5.1.1所示,第1条信息指示程序第6行 有错误,给出的提示是add没有定义,实际上,程序中add()函数己经定义,却提示没有定义, 此时应考虑到程序中是否漏掉了函数声明,在此例子中可以看到,自定义函数dd()函数在主 调函数mai()的后面,而编译是从上到下逐行进行的,如果没有函数的声明部分,当编译到 包含函数调用的语句 -84-
的问题,这些问题都是初学者经常容易犯的错误,针对函数的定义及调用这一节,主要有如 下问题: 1) 当使用用户自定义函数时,若该函数的位置在主调函数的后面,在主调函数中没有 对被调函数做声明; 2) 函数类型和函数的返回值类型不一致。 针对上面的问题,查找下面程序中存在的问题,并改正调试。 1.打开 c:\c-programming\5\pg5101.cpp,该程序是求两个数的和,有一个小问题,请修改, 使程序能正确运行。修改后的程序以 pg5101_ok.cpp 保存。该源程序内容如下: #include void main(void) { float a,b,c; printf("请输入两个数,中间用逗号隔开:"); scanf("%f,%f",&a,&b); c=add(a,b); printf("两个数之和为:%f\n",c); } float add(float x,float y) { float z; z=x+y; return z; } 提示:如何发现问题? 编译该程序,系统报告两个编译出错信息,如图 5.1.1 所示,第 1 条信息指示程序第 6 行 有错误,给出的提示是 add 没有定义,实际上,程序中 add( )函数已经定义,却提示没有定义, 此时应考虑到程序中是否漏掉了函数声明,在此例子中可以看到,自定义函数 add( )函数在主 调函数 main( )的后面,而编译是从上到下逐行进行的,如果没有函数的声明部分,当编译到 包含函数调用的语句 - 84 -
c-add(a,b); 时,编译系统不知道add是否为函数名,也无法判断实参a和b的类型和个数是否正确, 因而无法进行正确性的检查,此错误属于语法错误,当我们把第1个错误纠正之后,第2个 错误自动消失。 注意:在编译出错的情况下,请按照从上到下的顺序纠正错误,因为有些错误提示是前 面的错误引起的,所以当我们纠正了某个错误,有些错误提示就自动消失。 凶pg5101.cpp c:\c-programming\5\pg5101.cpp(7):error C2065:'add':undeclared identifier c:\c-programming\5\pg5101.cpp(7):warning C4244:'=conversion from 'int' c:c-programmingpe():error c2373:add:redefinition;differ 代譯撒查我发件1人入查我文件丁山 Ln 10,Col 1 REC COL OVR READ 图5.1.1程序编译后的错误信息 改正程序后的运行结果示例如图5.1.2所示: c "C:\c-programming\5\Debug\pg5101_ok.exe" 回 请输入两个数,中间用逗号隔开:3.5 两个数之和为:8.00000 Press any key to continue 图5.1.2pg5101_ok.cpp的运行结果 2.打开c:lc-programming\5pg5102.cpp,该程序是求两个数的最大值,有个小问题,请修 改,使程序能正确运行。修改后的程序以pg5102ok.cpp保存。该源程序内容如下: #include void main(void) float a,b,c; int max(float x,float y); printf("请输入两个实数,中间用逗号分隔:"); scanf("%f,%f",&a,&b); c=max(a,b)月 printf"两个数的最大值为:%fn",c方 } int max(float x,float y) -85-
c=add(a,b); 时,编译系统不知道 add 是否为函数名,也无法判断实参 a 和 b 的类型和个数是否正确, 因而无法进行正确性的检查,此错误属于语法错误,当我们把第 1 个错误纠正之后,第 2 个 错误自动消失。 注意:在编译出错的情况下,请按照从上到下的顺序纠正错误,因为有些错误提示是前 面的错误引起的,所以当我们纠正了某个错误,有些错误提示就自动消失。 图 5.1.1 程序编译后的错误信息 改正程序后的运行结果示例如图 5.1.2 所示: 图 5.1.2 pg5101_ok.cpp 的运行结果 2.打开 c:\c-programming\5\pg5102.cpp,该程序是求两个数的最大值,有个小问题,请修 改,使程序能正确运行。修改后的程序以 pg5102_ok.cpp 保存。该源程序内容如下: #include void main(void) { float a,b,c; int max(float x,float y); printf("请输入两个实数,中间用逗号分隔:"); scanf("%f,%f",&a,&b); c=max(a,b); printf("两个数的最大值为:%f\n",c); } int max(float x,float y) { - 85 -
float z: if(x>y) Z-X: else z-y, return z; 了提示:如何发现问题? 编译、链接该程序,系统未报告任何错误信息,但是运行该程序时,正确输入两个实数 之后,输出结果却出现问题:打印输出的最大值的小数部分丢失,主要原因在于函数的返回 值类型和函数类型不一致,max()函数的类型为int类型,而函数返回值z变量的类型为oat 类型,当两者类型不一致时,系统以函数类型为准,所以max(a,b)的函数结果是一个it类型 的数据,该函数结果赋值给变量c,最终导致最大值的小数部分丢失。 改正程序后的运行结果示例如图5.1.3所示。 可'C:\e-programsing\5\Debugipg5102.ok.exe回冈 情输入两个实数,中间用逗号分隔:3.2.6.7 两个数的最大值为:6.?886gg Press any key to continue 4 图5.1.3pg5102_ok.cpp的运行结果 二、程序扩展 1.打开c:lc-programming5pg5201.cpp,该程序是通过调用函数来实现求两个整数的最大 值问题。该源程序内容如下: #include void main(void) int a,b,d; int max(int x,int y); printf("请输入两个整数,中间用逗号分隔:"); scanf("%d,%d",&a,&b); -86-
float z; if (x>y) z=x; else z=y; return z; } 提示:如何发现问题? 编译、链接该程序,系统未报告任何错误信息,但是运行该程序时,正确输入两个实数 之后,输出结果却出现问题:打印输出的最大值的小数部分丢失,主要原因在于函数的返回 值类型和函数类型不一致,max( )函数的类型为 int 类型,而函数返回值 z 变量的类型为 float 类型,当两者类型不一致时,系统以函数类型为准,所以 max(a,b)的函数结果是一个 int 类型 的数据,该函数结果赋值给变量 c,最终导致最大值的小数部分丢失。 改正程序后的运行结果示例如图 5.1.3 所示。 图 5.1.3 pg5102_ok.cpp 的运行结果 二、程序扩展 1.打开 c:\c-programming\5\pg5201.cpp,该程序是通过调用函数来实现求两个整数的最大 值问题。该源程序内容如下: #include void main(void) { int a,b,d; int max(int x,int y); printf("请输入两个整数,中间用逗号分隔:"); scanf("%d,%d",&a,&b); - 86 -
d=max(a,b); printf"%d和%d两者的最大值为:%dn",a,b,d); } int max(intx,inty) int z: if(x>y) Z-X, else z-y, return z: } 要求:修改上面的程序,将ax()函数定义进行修改,实现求三个整数的最大值问题。修 改后的程序以pg520la.cpp保存。 训练要点:读懂程序中通过定义ax()函数,来实现求两个整数最大值问题,体会函数是 一个完成特定工作的独立程序模块,用户可以根据自己的需要自定义函数,程序中一旦调用 该函数,该函数将完成特定的工作,在此基础上,修改自定义函数max(),将max()函数的功 能加以改变,实现求三个整数的最大值问题。 修改后程序的运行结果如图5.1.4所示。 c "C:\c-programming\5\Debug\pg5201a.exe" 回x 请输入三个整数,中间用逗号分隔:21.3 2、1、3三个整数的最大值为:3 Press any key to continue 4 图5.1.4pg5201a.cpp的运行结果 2.打开c:lc-programming\5pg5202.cpp,该程序是已知三个整数,求它们的平方之和与平 均值之间的差值。该源程序内容如下: #include void main(void) int a,b.c; -87-
d=max(a,b); printf("%d 和%d 两者的最大值为:%d\n",a,b,d); } int max(int x,int y) { int z; if (x>y) z=x; else z=y; return z; } 要求:修改上面的程序,将 max( )函数定义进行修改,实现求三个整数的最大值问题。修 改后的程序以 pg5201a.cpp 保存。 训练要点:读懂程序中通过定义 max( )函数,来实现求两个整数最大值问题,体会函数是 一个完成特定工作的独立程序模块,用户可以根据自己的需要自定义函数,程序中一旦调用 该函数,该函数将完成特定的工作,在此基础上,修改自定义函数 max( ),将 max( )函数的功 能加以改变,实现求三个整数的最大值问题。 修改后程序的运行结果如图 5.1.4 所示。 图 5.1.4 pg5201a.cpp 的运行结果 2.打开 c:\c-programming\5\pg5202.cpp,该程序是已知三个整数,求它们的平方之和与平 均值之间的差值。该源程序内容如下: #include void main(void) { int a,b,c; - 87 -
float ave,s; int square(int x.int y,int z); printf("请输入三个整数,中间用逗号分隔:"方 scanf("%d,%d,%d",&a&b,&c); ave=(a+b+c)/3.0; s=square(a,b,c)-ave; printf"%d、%d、%d三个整数平方之和与平均值之间的差值为:%.2fn",a,b,c,s; } int square(int x,int y,int z) int m; m=x*x+y*y+z*z; return m; } 要求l:修改上面的程序,将求平均值问题用函数来实现,函数名为average,修改后的 程序以pg5202a.cpp保存。 要求2:修改上面的程序,将求三个整数平方之和与平均值之间的差值问题用函数来实现, 函数名为sub,修改后的程序以pg5202b.cpp保存。 训练要点:读懂程序中通过自定义square()函数,实现求三个整数平方之和功能的思路, 了解函数实际上是一个完成特定工作的独立程序模块,在程序设计中,常将一些常用的功能 模块编写函数,供其他函数调用,要善于利用函数,以减少重复编写程序段的工作量,在此 基础上,按照要求1将求平均值的功能模块编写成函数,按照要求2将求平方数之和与平均 值差值的功能模块编写成函数。 要求1修改后程序的运行结果如图5.1.5所示。 e"C:\c-programming\5\Debug\pg5202a.exe 回 请输入三个整数,电中间用逗号分隔:123 1、2、3这三个整数苹方之和与平均值之间的差值为:12.0 Press any key to continue 图5.1.5pg5202a.cpp的运行结果 要求2修改后程序的运行结果如图5.1.6所示。 -88-
float ave,s; int square(int x,int y,int z); printf("请输入三个整数,中间用逗号分隔:"); scanf("%d,%d,%d",&a,&b,&c); ave=(a+b+c)/3.0; s=square(a,b,c)-ave; printf("%d、%d、%d 三个整数平方之和与平均值之间的差值为:%.2f\n",a,b,c,s); } int square(int x,int y,int z) { int m; m=x*x+y*y+z*z; return m; } 要求 1:修改上面的程序,将求平均值问题用函数来实现,函数名为 average,修改后的 程序以 pg5202a.cpp 保存。 要求 2:修改上面的程序,将求三个整数平方之和与平均值之间的差值问题用函数来实现, 函数名为 sub,修改后的程序以 pg5202b.cpp 保存。 训练要点:读懂程序中通过自定义 square( )函数,实现求三个整数平方之和功能的思路, 了解函数实际上是一个完成特定工作的独立程序模块,在程序设计中,常将一些常用的功能 模块编写函数,供其他函数调用,要善于利用函数,以减少重复编写程序段的工作量,在此 基础上,按照要求 1 将求平均值的功能模块编写成函数,按照要求 2 将求平方数之和与平均 值差值的功能模块编写成函数。 要求 1 修改后程序的运行结果如图 5.1.5 所示。 图 5.1.5 pg5202a.cpp 的运行结果 要求 2 修改后程序的运行结果如图 5.1.6 所示。 - 88 -
"C:\c-programming\5\Debug\pg5202b.exe" 回 请输入三个整数,中间用逗号分隔:123 1、2、3这三个整数平方,之和与平均值之间的差值为:12.0 Press any key to continue 4 图5.1.6pg5202b.cpp的运行结果 3.打开c:lc-programming5pgS203.cpp,该程序是通过调用函数prime()来判断m是否为 素数,求100以内的全部素数。该源程序内容如下: #include #include void main(void) int x; int prime(int m); printf("以下是100以内的素数:n")方 for(X=2,x<=100,x+) if (prime(x)) printf("%6d",x方 printf("n"方 int prime(int m) int i.n.flag=1: n=sqrt(m)月 for(i=2:i<=ni++)) if(m%i-=0) flag-0; return flag; } 要求:修改上面的程序,将函数prime()修改成没有返回值的函数,修改后的程序以 pg5203a.cpp保存。 -89-
图 5.1.6 pg5202b.cpp 的运行结果 3.打开 c:\c-programming\5\pg5203.cpp,该程序是通过调用函数 prime( )来判断 m 是否为 素数,求 100 以内的全部素数。该源程序内容如下: #include #include void main(void) { int x; int prime(int m); printf("以下是 100 以内的素数:\n"); for (x=2;x<=100;x++) if (prime(x)) printf("%6d",x); printf("\n"); } int prime(int m) { int i,n,flag=1; n=sqrt(m); for (i=2;i<=n;i++) if (m%i==0) flag=0; return flag; } 要求:修改上面的程序,将函数 prime( )修改成没有返回值的函数,修改后的程序以 pg5203a.cpp 保存。 - 89 -