实验6 函数与编译预处理
函数与编译预处理
函数与编译预处理一、函数的定义1、无参函数的定义形式类型标识符函数名()第一行:函数首部{声明部分语句 { }包含的:函数体}例1:void fun( ){printf(“Hello!\n”);}2、有参函数的定义形式类型标识符函数名(形式参数列表){声明部分语句}例2:int max(int x, int y){ int z;z = x > y ? x : y;return (z);}注:“类型标识符”是指函数值的类型。
若省略,默认为int。
二、函数的调用无参函数:函数名()有参函数:函数名(实际参数列表)例3:在main函数中调用fun和max函数void main( ){int m,n,t;scanf(“%d,%d”,&m,&n);t=max(m,n); /*调用max函数*/fun(); /*调用fun函数*/printf(“max number is %d\n”,t);}注:1、C语言程序由函数构成,其中有且仅有一个main函数,各函数书写的先后顺序任意。
2、函数的定义是相互独立的,不能在一个函数的内部定义另一个函数,即函数的定义不能嵌套。
3、程序从main函数开始执行,其他函数被调用时执行,调用完后回到主调函数,最后在main函数中结束整个程序。
三、函数的声明在主调函数中一般要对被调函数进行声明。
声明的作用是告知编译器被调函数的函数名、函数类型、参数个数和参数类型,方便进行语法检查。
声明的形式:类型标识符函数名(形式参数列表);即:函数首部加分号例如:void fun( );int max(int x, int y);其中参数名称可省略,如:int max(int , int );Turbo C在以下两种情况中,可省略函数声明:1、被调函数定义在主调函数前。
2、被调函数类型为int、char。
四、参数的传递1、形参是变量,但函数被调用时才被分配内存,调用完毕,所占内存将被释放。
第6章函数与编译预处理
main() 例 比较两个数并输出大者 { int a,b,c;
scanf("%d,%d",&a,&b);
c=max(a,b); (main 函数) c=max(a,b);
实参
max(int x, int y)(max 函数) printf("Max is %d",c);
a=printstar(); printf("%d",a); }
输出:10
void printstar() { printf("**********"); } main() { int a;
a=printstar(); printf("%d",a); }
编译错误!
上一页
下一页
例 函数返回值类型转换
上一页
下一页
例 交换两个数
swap(int *p1,int *p2) { int p;
调前:
a 5
b 9
p=*p1; *p1=*p2;
p1
a
&a
5
*p2=p; }
调swap:
p2
b
main()
&b
9
{ int a,b;
p1
a
scanf("%d,%d",&a,&b);
&a
9
printf(“a=%d,b=%d\n”,a,b); 交换:
调用函数b
b函数
上一页
下一页
long fac(int k) {long f=1; int i; for(i=1;i<=n;i++)
C语言 函数与编译预处理
main() {
int i, m, s=0; for (i=1; i<6; i++)
{ m=mul( i ); s+=fact( m );
} printf(“%d\n”, s); }
函数的递归调用
函数的递归 函数自身
在调用函数的过程中,该函数又去调用 int f (int x)
补充:编写一个函数isprime(int a)用来判断自变 量a是否是素数,若是,返回数值1,否则返回数值0。
开始 输入a, flag=1 调用判断函数
算法思想: 只能被 1 和其本身整
除的数,称为素数
Y
N
是素数?
flag=1
返回
flag=0
查看源程序
补充:利用isprime函数,编程验证任意一个偶数可 以写成两个素数之和。
查看源程序
6.4 函数的嵌套与递归调用
函数的嵌套 在调用函数的过程中,又去调用另一个函数
main()
sub1()
sub2()
例6.6 计算 s = (1*1)!+(2*2)!+(3*3)!+...+(6*6)!
算法分析:n!可定义为一个函数fact( int n ) ( k*k)的运算也可以定义为一个函数mul( int k ) 计算s本身是一个循环程序
int n; scanf( “%d”, &n ); printf(“%d\n”,sum(n)); }
int sum ( int n ) {
int s=0; int k; for( k=1;k<=n; k++)
s= s + k; return s; }
函数与编译预处理实验报告
函数与编译预处理实验报告一、实验目的本次实验旨在通过编写程序,掌握函数与编译预处理的相关知识,了解函数的调用和返回机制以及编译预处理的作用。
二、实验环境操作系统:Windows 10开发工具:Code::Blocks 17.12编程语言:C语言三、实验内容1. 函数的定义和调用函数是C语言中的一个重要概念,它可以将一段代码封装成一个功能单元,方便代码重用和维护。
在本次实验中,我们需要掌握如何定义函数,并且了解函数的调用过程。
在C语言中,函数通常由以下几部分组成:返回类型函数名(参数列表){函数体;return 返回值;}其中,返回类型指定了函数返回值的类型;函数名是唯一标识符,用于调用该函数;参数列表指定了该函数需要传入的参数;函数体是一段具体的代码逻辑;return语句则将结果返回给调用者。
在调用一个函数时,我们需要按照以下格式进行:返回值变量 = 函数名(参数列表);其中,返回值变量接收该函数返回的结果;参数列表则按照定义顺序传入相应参数。
如果该函数不需要传入任何参数,则可以省略参数列表。
2. 函数指针除了直接调用一个已经定义好的函数外,我们还可以使用函数指针来间接调用一个函数。
函数指针和普通指针类似,它指向的是一个函数的地址。
通过函数指针,我们可以在运行时动态地确定需要调用哪个函数。
在C语言中,声明一个函数指针的方法如下:返回类型 (*指针变量名)(参数列表);其中,括号中的*表示这是一个指针变量;指针变量名则是该变量的标识符;参数列表和返回类型与被指向的函数相同。
通过以下代码可以将一个已经定义好的函数赋值给一个函数指针:int max(int a, int b){return a > b ? a : b;}int (*p)(int, int) = max;在上述代码中,p就是一个用于存储max函数地址的函数指针。
3. 编译预处理编译预处理是C语言中一项重要的功能,在编译过程中会对源代码进行一些预处理操作。
函数与编译预处理06
以下程序的运行结果是:#define DEBUG void main(void){ int a=14, b=15, c; c=a/b;# ifdef DEBUGcout<<cout<<““a=a=““<<oct<<a<<<<oct<<a<<““ b= b=““<<b<<endl; # endifcout<< cout<<““c=c=““<<dec<<c<<endl;}输出:a=16,b=17c=0程序的多文件组织而在设计一个功能复杂的大程序时,为了便于程序的设计和调试,通常将程序分成若干个模块,把实现一个模块的程序或数据放在一个文件中。
当一个完整的程序被存放在多于一个文件中时,称为程序的多文件组织。
int q(int x){ int y=1;static int z=1;z+=z+y++;return x+z;}4 9 18 void main(void){ cout<<q(1)<<{ cout<<q(1)<<‘‘\t\t’’;cout<<q(2)<<cout<<q(2)<<‘‘\t\t’’;cout<<q(3)<<cout<<q(3)<<‘‘\t\t’’;}void f(int n){ if(n>=10)f(n/10);cout<<n<<endl; }void main(void) { f(12345);}112 123 1234 12345void main(void){ char s; cin.get(s); while(s!= while(s!=‘‘\n \n’’) { switch(s- { switch(s-’’2’) { case 0:case 1: cout<<s+4;case 2: cout<<s+4;break; case 3: cout<<s+3;default: cout<<s+2; break; }cin.get(s); }cout<<endl;}输入:2347<CR>545455555657。
c语言 第六章 函数与编译预处理2
#elif和#else可以 #elif和#else可以 没有
如果条件1为真就编译程序段1 如果条件1为真就编译程序段1, 否则如果条件2 否则如果条件2为真就编译程序段 2,…,如果各条件都不为真就编译 #endif必须存在 #endif必须存在,它 必须存在, 程序段n 程序段n。 #if命令的结尾 是#if命令的结尾 #if和#elif常常与 #if和#elif常常与defined命令配合 常常与defined命令配合 使用,defined命令的格式为 命令的格式为: 使用,defined命令的格式为:
预编 译处 理后
a = 3.14; * 2 * 2;
错误! 错误!
宏可以被重复定义 宏可以被重复定义。 重复定义。 #define N 10 /*第一次宏定义 第一次宏定义*/ 第一次宏定义 fun( ) 输出结果: 输出结果: { 2010 printf(“%d”,N ); /* 输出 */ 输出10 } #define N 20 /*第二次宏定义 第二次宏定义*/ 第二次宏定义 void main ( ) { printf ("%d", N ); /* 输出 */ 输出20 fun( ); }
例:下面的程序利用ACTIVE_COUNTRY定义货币的名称 下面的程序利用ACTIVE_COUNTRY定义货币的名称
#define #define #define #define USA 0 ENGLAND 1 FRANCE 2 ACTIVE_COUNTRY USA
#if ACTIVE_COUNTRY == USA char *currency = “dollar”; //有效 //有效 #elif ACTIVE_COUNTRY == ENGLAND char *currency = "pound" ; #else char *currency = "france" ; char *currency = “dollar”; #endif
实验6 函数与编译预处理
实验六函数与编译预处理(4学时)实验前必须做的操作...............——..新建文件夹:1、先在对应的K:盘上建立一个父文件夹(用来存放本人整个学期的作业),格式为:“专业+班级+学号+姓名”,如:工业1091班、学号为05的匡珍春同学,其父文件夹名称为:工业109105匡珍春,然后在此父文件夹下建立子文件夹,名称为:实验6(用来存放实验6需要上交的文件)。
2、在E:盘上建立一个以本人姓名为名称的文件夹(本次实验的工作文件夹),例如:E:\匡珍春【实验目的】1、掌握自定义函数的一般结构及定义函数的方法;2、掌握函数的形式参数、实际参数、函数返回值等重要概念;3、掌握函数实参与形参间的“值传递”方式;4、掌握函数声明、函数调用的一般方法;5、掌握模块化程序设计思想,会采用C语言中函数进行模块化程序设计;6、掌握全局变量和局部变量作用域以及全局变量和局部变量的使用方法;7、掌握函数的嵌套调用的程序的执行过程,会使用嵌套调用设计程序;8、掌握使用函数递归调用的程序的执行过程,会使用递归程序解决实际问题;9、理解宏的概念,掌握宏定义。
了解文件包含的概念,掌握其用法;10、学习对多文件程序的编译和运行;11、熟练掌握VC程序调试方法,包括断点的设置和取消,以及单步执行跟踪进入函数和跳出函数的方法。
【实验内容】[实验任务一]:断点的设置和取消、单步执行跟踪进入函数和跳出函数方法练习程序跟踪调试实例6-1:调试示例(请仔细按以下各步骤进行操作):从键盘输入一个正整数n,计算n! 的值,要求定义和调用函数fact(n),计算n!。
Input n: 1010! = 3628800说明:实验五中我们使用了程序运行到光标位置调试程序,本次实验需要掌握设置断点,以及单步调试进入函数和跳出函数的方法。
【操作步骤】:(1)输入源程序,并以error6_1.c文件名最终保存在实验6文件夹里,编译程序,出现警告信息:双击该警告信息,箭头指向“f=fact(n);”这一行,警告信息指出函数“fact”没有定义,而函数“fact”实际上已经定义了,这是为什么呢?因为函数在调用之前,必须先声明。
实验六 函数与编译预处理
实验六函数与编译预处理1.void main(){float a,b,c;scanf("%f%f",&a,&b);c=add(a,b);printf("sum is %f\n",c);}float add(float x,float y){float z;z=x+y;return(z);}//错误的地方,(1)没有包含头文件<stdio.h> (2)函数定义应该在函数调用的前面. 更正后的程序:#include<stdio.h>float add(float x,float y){float z;z=x+y;return(z);}void main(){float a,b,c;scanf("%f%f",&a,&b);c=add(a,b);printf("sum is %f\n",c);}2.void main(){int a=3,b=6;printf("a=%d,b=%d\n",a,b);exchange1(a,b);printf(:a=%d,b=%d\n",a,b);}void exchange1(int x,int y){int t;t=x;x=y;y=t;printf("x=%d,y=%d\n",x,y);}//错误的地方,(1)没有包含头文件<stdio.h> (2)函数定义应该在函数调用的前面.更正后的程序:#include<stdio.h>void exchange1(int x,int y){int t;t=x;x=y;y=t;printf("x=%d,y=%d\n",x,y);}void main(){int a=3,b=6;printf("a=%d,b=%d\n",a,b);exchange1(a,b);printf("a=%d,b=%d\n",a,b);}3.long int fac(int n){long int p;int i;p=1;for(i=1;i<=n;i++)p=p*i;return(p);}int cmn(int m,int n){int x;x=fac(m)/(fac(n)*fac(m-n));return(x);}void main(){int m,n,c;scanf("%d%d",&m,&n);c=cmn(m,n);printf("c=%d\n",c);}//应该加个#include<stdio.h> 头文件4.int a=7,b=9;void main(){int i,a=5,x=80,y=60;for(i=1;i<4;i++){printf("a=%d,b=5d,max=%d\n",a,b,max(a,b));b+=6;}printf("result_sum=%d\n",sum(x,y));}int sum(int x,int y){extern int m,n;int temp;temp=x+y+m+n+a+b;return(temp);}int m=12,n=25;int max(int 1,int b){return(a>b?a:b);}程序更正:#include<stdio.h>int a=7,b=9;void main(){int i,a=5,x=80,y=60;int max(int a,int b);int sum(int x,int y);for(i=1;i<4;i++){printf("a=%d,b=5d,max=%d\n",a,b,max(a,b));b+=6;}printf("result_sum=%d\n",sum(x,y));}int sum(int x,int y){extern int m,n;int temp;temp=x+y+m+n+a+b;return(temp);}int m=12,n=25;int max(int a,int b){return(a>b?a:b);}5.调试运行以下程序.#include<stdio.h>int fun(int a){int b=0;static int c=2;b+=c;c+=1;return(a+b-c);}void main(){int a=3,i;for(i=0;i<3;i++) printf("%4d",fun(a));}6.略7.略8.#include<stdio.h>#define DEBUGvoid main(){int a=14,b=15,temp;temp=a/b;#ifdef DEBUGprintf("a=%d,b=%d",a,b);#endifprintf("temp=%d\n",temp);}程序结果为:a=14,b=15,temp=0(1)第二行中,宏定义是可以没有具体的值的,在这里只是定义了一个宏名.DEBUG没有值.(2)第7~9行为:#ifdef DEBUGprintf("a=%d,b=%d",a,b);#endif会被编译,因为种种原因DEBUG已经被定义过.(3)如将第2行删除,程序运行结果为:temp=0 因为没有定义DEBUG,所以原来第7~9行的程序没有执行.(4)第9行不能删除,因为#ifdef 和#endif必须成对出现.9.编程题#include<stdio.h>long int fac(int n){long int p;int i;p=1;for(i=1;i<=n;i++)p=p*i;return(p);}void main(){int m,n,c;scanf("%d%d",&m,&n);c=fac(n)/(fac(n-m)*fac(m));printf("c=%d",c);}。
C语言编译预处理实验报告
C 语言编译预处理实验报告实验名称:编译预处理一. 实验目的(1) 掌握文件包含、宏定义、条件编译、assert 宏的使用。
(2)练习带参数的宏定义、条件编译的使用。
( 3)练习assert 宏的使用。
(4)使用集成开发环境中的调试功能:单步执行,设置断点,观察变量。
二、实验内容1. 源程序改错:源程序:#include <stdio.h> #define SUM a+b #define DIF a-b #define SWAP(a,b)a=b, b=aint main(){int b, t;printf("Input two integers a,b:"); scanf("%d, %d", &a, &b);printf("\nSUM=%d\n the difference between square of a andsquare b is:%d",SUM,SUM*DIF);SWAP(a,b);Printf("\nNow a=%d,b=%d\n", a, b); return 0;}.2. 源程序修改替换源程序:voidmain(void){int a, b, c;float d, e;printf("Enter three integers:"); scanf("%d, %d, %d", &a, &b, &c);printf("\nthe maximum of them is %d\n", max(a,b,c)); printf("Enter two floating pointnumbers:");scanf("%f, %f", &d, &e); printf("\nthe sum of them is%f\n",sum(d,e));return 0;int max(int x, int y, int z){int t; if (x > y) t = x;elset = y;if (t < z)t = z; return t;}3. 跟踪调试程序程序代码:#define Rint main(void){float r, s; int s_integer = 0; printf("input a number:");scanf("%f", &r);#ifdef R s = 3.14159 * r * r; printf("area of round is:%f\n", s); s_integer = integer_fraction(s);printf("the integer fraction of area is %d\n", s_integer); assert((s-s_integer) < 1.0);#endifreturn 0;}int integer_fraction(float x){int i = x; return i; }4. 程序设计三、实验步骤及结果步骤:1.编写源程序2. 对源程序进行编译,修改错误,运行修改后的程序3•发现结果有误,进行调试。
C语言程序设计_06函数与编译预处理
注意:所有的递归问题都一定可以用非递归的算法实现,并 且已经有了固定的算法。如何将递归程序转化为非递归程序 的算法已经超出了本书的范围,感兴趣的读者可以参看有关 数据结构的文献资料。
6.5 变量的作用域与存储类别 6.5.1 变量的作用域 在程序中能对变量进行存取操作的范围称为变量的作用域。 根据变量的作用域不同,变量分为局部变量和全局变量。 1.局部变量 在一个函数体内或复合语句内定义的变量称为局部变量。局 部变量只在定义它的函数体或复合语句内有效,即只能在定 义它的函数体或复合语句内部使用它,而在定义它的函数体 或复合语句之外不能使用它。
(3)将分解后的每个小问题作为一个整体,描述用这 些较小的问题来解决原来大问题的算法。 由第(3)步得到的算法就是一个解决原来问题的递归 算法。由第(1)步将问题的规模缩到最小时的条件就 是该递归算法的递归结束条件。 【例6.7】利用递归函数打印如图6-7所示的数字金字塔 图形。
图6-7 数字金字塔
2.函数体 在函数定义的最外层花括号括起来的部分称作函数体。在函 数体的前面部分可以包含函数体中程序对象的声明和变量定 义,声明和定义之后是描述函数功能的语句部分。 函数体中的RETURN语句用于传递函数的返回值。一般格式 为: RETURN 表达式;
说明: (1)一个函数中可以有多个RETURN语句,当执行到某个 RETURN语句时,程序的控制流程返回调用函数,并将 RETURN语句中表达式的值作为函数值带回。 (2)若函数体内没有RETURN语句,就一直执行到函数体 的末尾,然后返回调用函数。这时也有一个不确定的函数值 被带回。 (3)若不需要带回函数值,一般将函数定义为VOID类型。 (4)RETURN语句中表达式的类型应与函数返回值的类型 一致。不一致时,以函数返回值的类型为准。 3.空函数 C语言还允许函数体为空的函数,其形式为: 函数名() {} 调用此函数时,什么工作也不做。
函数与编译预处理实验报告
函数与编译预处理实验报告1. 背景函数与编译预处理是计算机编程中非常重要的两个概念,它们对于程序的结构和执行效率都起着关键作用。
函数是一段可重复使用的代码块,通过将任务划分为多个函数可以提高代码的可读性与维护性。
而编译预处理则是在编译过程中对源代码进行预处理,包括宏展开、文件包含和条件编译等操作。
本次实验通过设计并实现一段使用函数和编译预处理的程序,旨在加深对函数和编译预处理的理解,掌握它们的基本概念和使用方法,并通过实践感受它们对程序结构和性能的影响。
2. 分析2.1 需求在实验中,我们需要设计一个问题,通过函数和编译预处理来实现对问题的解决。
首先,我们需要确定问题的具体要求和输入输出规范。
只有明确了问题的需求,才能设计出合适的函数和合理的编译预处理指令。
2.2 设计根据实验要求,我们可以设计一个简单的问题:计算一个整数的平方。
用户输入一个整数,程序输出该整数的平方。
这是一个简单的计算问题,可以通过函数和编译预处理来实现。
我们可以设计一个函数calculate_square用于计算平方,并通过编译预处理指令来实现输入输出的控制。
具体的实现细节如下:#include <stdio.h>// 函数:计算平方int calculate_square(int x) {return x * x;}// 编译预处理指令:实现输入输出控制#define ENABLE_INPUT_OUTPUT#ifdef ENABLE_INPUT_OUTPUTint main() {int num;printf("Please enter an integer: ");scanf("%d", &num);int result = calculate_square(num);printf("The square of %d is %d.\n", num, result);return 0;}#endif上述代码中,我们定义了一个函数calculate_square用于计算整数的平方。
第6章 函数与编译预处理PPT课件
上一页
下一页
模块与函数
C语言程序由基本语句和函数组成,每个函数可完成相 对独立的任务,依一定的规则调用这些函数,就组成了解决 某个特定问题的程序。任务、模块与函数的关系:
任务
模块
模块
模块
函数 函数 函数 函数
函数
函数
上一页
下一页
看这样一个问题:求[200,1000]的双胞胎数的对数。双胞胎数:两素数差 为2称为双胞胎数。
这是我们上一章结束的一道练习题,下面的左边是我们当时编的程序。
main( ) { int a,b,n=0,I;
for(a=200;a<=998;a++) { for(I=2;I<a;I++)
if(a%I==0) break; if(a==I)
我们注意到,程序中用 筐住的部分 是完成了相同的功能,即判断一个数(a 或b)是否是素数。我们可以考虑用一个 独立的函数来完成判断素数的功能,在 主函数中调用此函数即可。如下:
教学重点:
函数的定义及调用、递归调用、 变量的作用域。
上一页
下一页
6.1模块化程序设计与函数
在设计较复杂的程序时,我们一般采用的方 法是:把问题分成几个部分,每部分又可分成更 细的若干小部分,逐步细化,直至分解成很容易 求解的小问题。这样的话,原来问题的解就可以 用这些小问题来表示。
把复杂任务细分成多个问题的过程,就叫程 序的模块化。模块化程序设计是靠设计函数和调 用函数实现的。
上一页
下一页
标准库函数
C语言有丰富的库函数,这些函数的说明在 不同的头文件(*.h)中。想要调用标准的库函数, 就必须“include”包含相应头文件。
例如:
d06_函数与编译预处理解读
退出
递归调用
#include <stdio.h> void main() { int x,y,z,n; int max(int a, int b); x=2; y=8; z=-12; //调用max找出x、y、z的最大值 //并赋值给变量n n = max(y, z); n = max(x, n); printf(“最大值是%d\n”,n) } 第六章 函数与编译预处理 int max(int a, int b) { int m; if(a>b) m=a; else m=b; return m; }
(1) 主函数开始执行时,给实际参数分配存 储空存储变量值。 (2) 函数调用时,给形式参数分配空间,实 际参数传值给对应的形式参数。 (3) 实际参数和形式参数占用不同的存储空 间。
//被调用的自定义函数swap void swap(int a,int b) { int temp; if(a<b) { temp=a; a=b; b=temp; } }
分析程序的功能: (1) 输出20个* (2) 计算两数之和 (3) 找出两数之间的大值
第六章 函数与编译预处理
退出
自定义函数
用户根据实际需求先定义函数,然后通过调用执 行函数,实现函数的功能。
运算类函数:为了完成某类运算,函数执行结束 后会得到运算结果,通常需要将这个结果反馈给 调用它的函数。 操作类函数:为了完成某类操作,函数的执行过 程对应一系列操作,这类函数通常不需要产生反 馈结果。
n = max(x, max(y,z));
退出
递归调用prg6-6.c
编程计算n!,其中n从键盘输入。
#include <stdio.h> void main() 如果要求设计自定义函数计算n!, { 程序该如何编写呢? int i,n; long result=1; printf("从键盘输入变量n的值\n"); scanf("%d",&n); for(i=1;i<=n;i++) result=result*i; printf("%d!=%d\n",n,result); } 第六章 函数与编译预处理 退出
函数与预编译处理
#include<stdio.h> int max(int x,int y) { return x>y?x:y; } void main() { int a,b,c,m; printf ("请输入3个整数:\n"); scanf("%d%d%d",&a,&b,&c); m=max(c,max(a,b)); printf ("m=%d\n",m); }
【例6.5】 求1!+2!+3!+4!+5!。
#include<stdio.h> /* 不是语句,末尾不加分号 */ int fact(int n) /* 求n!函数 */ { int j,f=1 ; for(j=1;j<=n;j++) f=f*j ; return f; /* 返回main函数 */ } void main() { int k, sum=0 ; for(k=1;k<=5;k++) sum=sum+fact(k); printf("sum=%d\n",sum); }
#include<stdio.h> void main() { float x, y; int n ; float power(float x,int n); /* power()函数的提前声明 */ scanf("%f%d", &x,&n); y=power(x, n); printf("y=%.2f\n", y ); } float power(float x,int n) { int i; float t=1; for(i=1;i<=n;i++) t=t*x; return t; }
第六章-函数与编译预处理命令
2.函数的定义和说明
补充说明: 1. 空函数——既无参数、函数体又为空的函数。 [函数返回值类型] 函数名(void) { } 2. 传统C语言的定义方式 例: double add(x,y) 类型 函数名称(参数表) 参数说明;
double x, y;
3. 如果有参数,则应对它们的类型一一作出说明。
4. 不能在一个函数内部再定义函数
5. 从语法规则上讲,函数类型可以是除函数和数组以外的任何类型 。但对一个具体函数的定义来说,它的类型是惟一的,并且通常 与其返回值的类型一致。如果不一致,系统自动转换。注意,缺 省的函数类型是int型。
2.函数的定义和说明
例: 被调函数,含形参 max(float x, float y) { 1. 注意采用了缺省函数 float z; 类型的定义方式,因此, z=x>y?x:y; 默认返回int型 return z; 2. 即使z是float型, } return语句将把z转化为 调用函数 main() int型,即去掉小数点 { 3. 由于max返回为int型,而c为 float a=1.5,b=0.5; float型,系统直接把max返回的 float c; int型量转换为float型,赋给c 带实参调用 c=max(a,b); printf(“max os %f\n”,c); 注意,由于没有在函数定义时指 } 定函数类型为float型,导致小数 运行结果: 点后的结果出错 Max is 1.000000 改正: float max(float x, float y)
函数的概述
从函数形式的角度进行分类 1. 无参函数:无参函数即在函数定义、函数说明及函 数调用中均不带参数。
2. 有参函数:有参函数也称为带参函数。在函数定义及 函数说明时都有参数,称为形式参数(简称为形参) 。
函数与编译预处理
例6.3 用递归方法计算n!。
long fact(int n) { if(n==0||n==1) return 1; else return n*fact(n-1); } main() { int n; long m; scanf("%d",&n); m=fact(n); printf("%d!=%ld\n",n,m); }
程序举例
1.以下程序的输出结果是 #define M(x,y,z) x*y+z main() {int a=1,b=2,c=3; printf(“%d\n”,M(a+b,b+c,c+a)); }
计算过程: 1+2*2+3+3+1=12
4+4*4+4/2+2*2+2=28
有以下程序执行后输出结果是 #define f(x) x*x main() {int i; i=f(4+4)/f(2+2); printf(“%d\n”,i); }
2.带参数的宏定义
带参数的宏定义的一般形式为: #define 宏名(形参表) 字符串 对带参数的宏,在调用时,不仅要宏展开,而且要用实参去代换形参。 带参数宏调用的一般形式为:宏名(实参表); #define MAX(x,y) x>y?x:y main() { int a,b,m; scanf("%d%d",&a,&b); m=MAX(a,b); printf("max=%d\n",m);
全局变量和局部变量的使用特点 变量存储类别
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验六函数与编译预处理(4学时)实验前必须做的操作...............——..新建文件夹:首先在各自对应的计算机ncre(k:)盘上对应座位号文件夹内新建一个文件夹,文件夹的名字为“班级+学号的后两位+姓名”,如座位号为K02,航海1111班、学号后两位是02的、姓名为“张强”的同学,则其对应的文件夹名字是:航海111102张强。
然后在刚才建好的文件夹里面再建立一个文件夹,文件夹为“实验6”。
【实验目的】1、掌握自定义函数的一般结构及定义函数的方法;2、掌握函数的形式参数、实际参数、函数返回值等重要概念;3、掌握函数实参与形参间的“值传递”方式;4、掌握函数声明、函数调用的一般方法;5、掌握模块化程序设计思想,会采用C语言中函数进行模块化程序设计;6、掌握全局变量和局部变量作用域以及全局变量和局部变量的使用方法;7、掌握函数的嵌套调用的程序的执行过程,会使用嵌套调用设计程序;8、掌握使用函数递归调用的程序的执行过程,会使用递归程序解决实际问题;9、理解宏的概念,掌握宏定义。
了解文件包含的概念,掌握其用法;10、学习对多文件程序的编译和运行;11、熟练掌握VC程序调试方法,包括断点的设置和取消,以及单步执行跟踪进入函数和跳出函数的方法。
【实验内容】[实验任务一]:断点的设置和取消、单步执行跟踪进入函数和跳出函数方法练习程序跟踪调试实例6-1:调试示例(请仔细按以下各步骤进行操作):从键盘输入一个正整数n,计算n! 的值,要求定义和调用函数fact(n),计算n!。
Input n: 1010! = 3628800说明:实验五中我们使用了程序运行到光标位置调试程序,本次实验需要掌握设置断点,以及单步调试进入函数和跳出函数的方法。
【操作步骤】:(1)输入源程序,并以error6_1.c文件名最终保存在实验6文件夹里,编译程序,出现警告信息:双击该警告信息,箭头指向“f=fact(n);”这一行,警告信息指出函数“fact”没有定义,而函数“fact”实际上已经定义了,这是为什么呢?因为函数在调用之前,必须先声明。
在主调函数的变量定义前面加上函数声明“long fact(int m);”后,重新编译,连接,都正确。
注意:如果将error6_1.c文件改为error6_1.cpp (即改为C++源程序文件)可见VC++系统对.c文件和.cpp文件在进行编译时,对语法的要求不完全一样,这一点希望同学们注意。
此处错误修改的方法与上面相同。
(2)调试开始,设置2个断点(断点的作用:程序执行到断点处暂停,使用户可以观察当前的变量或其它表达式的值,然后继续运行),先把光标定位到要设置断点的位置,然后单击编译工具条上的(Inert / Remove Breakpoint (F9)),断点就设置好了(如图6.1所示)。
如果要取消断点,只要把光标放到要取消的断点处,单击,这个断点就取消了。
图6.1 设置断点(3)单击编译工具条(go (F5)),运行程序,用户输入n的值10后,程序运行到第一个断点位置暂停(如图6.2所示)。
图6.2 程序运行到断点位置(4))单击(Step Into (F11))进入函数fact()调试,箭头表示程序已经执行到函数fact()内(如图6.3所示)。
(5)使用,在函数fact()中设置程序的第3个断点(如图6.3所示)。
图6.3 进入函数fact( )调试,并在运行时设置断点(6)单击(go (F5)),程序直接运行到断点处,暂停(如图6.4所示),在变量窗口观察到product 的值是-2903040,不正确,因为变量product未赋初值,加上语句product=1后,按以上的步骤,重新编译、连接,运行到第3个断点处,变量窗口中product的值正确。
图6.4 程序从函数fact()开始直接运行到第3个断点的位置(return前面)(7)现在需要从被调函数返回到主调函数,单击调试工具条中的(Step Out (Shift+F11)),程序返回主调函数继续执行(如图6.5所示)。
图6.5 程序回到了主调函数(8)继续单击(go (F5)),程序执行到最后(如图6.6所示),在运行窗口输出10!=3628800,与题目要求的结果一致。
图6.6 程序执行到最后(9)单击终止调试图标(Stop Debugging(Shaft+F5)),程序调试结束。
程序跟踪调试实例6-2:模仿示例调试以下程序,直到输出正确结果,将修改好的程序以error6_2.c为文件名最终保存在实验6文件夹里。
(需要存盘)程序功能:利用函数调用求“1!+2!+3!+4!+...+10!”的值(参见实验教材73页程序填空题第(2)小题)提示:改变main()函数中for循环的循环次数,让程序只求“1!+2!+3!”的值,更容易找到程序的错误。
程序跟踪调试实例6-3:综合调试、改错练习:以下程序有多处错误,请综合运用前面所学过的所有知识和VC++的调试手段,改正程序的各种错误,使其运行出正确的结果。
程序的功能是:利用函数调用求任意两个整数的和。
将修改好的程序以error6_3.c 为文件名最终保存在实验6文件夹里。
(需要存盘)【提示】:①本题中涉及到两个函数,分别是main()函数和sum()函数,而C语言程序中各个函数之间的关系是相互独立的,所以应该将int sum(a, b)函数写在主函数main()函数的外面,即将上面程序中的最后一行的}放在 int sum(a,b) 的上一行;②按以上方式修改以后,编译时会出现如下错误信息提示:Declaration syntax error in function main. 主函数中声明语法错误如何修改请参照ppt课件的C6 函数与编译预处理的第21~23的内容;③经过以上几步修改后,编译时会出现如下错误信息提示,且光标停留在scanf( )处:Possible use of 'x' before definition in function main. 在定义主函数之前可能已经使用了x 原因就是scanf()语句错误。
④修改后重新编译会出现错误信息提示如下所示:Redeclaration of ‘a' in function sum 在sum函数中重复声明了a造成此错误的原因是定义sum( )函数错误,如何修改,请参照ppt课件的C6函数与编译预处理的第7~8的内容;⑤修改完成以后,编译成功,但连接时(即按compile菜单下的Make EXE file选项)时,会出现如下错误信息提示:Undefined symbol '_sam' in module example2.c 在example2.c模块中没有定义符号sam 造成此错误的原因就是:被调函数的函数名与主调函数中调用被调函数的函数名不一致。
修改方法可将主调函数中的sam改成sum以保持一致;⑥修改后重新编译,出现信息提示:Too few parameters in call to ‘sum’ in functionmain 主函数中调用sum函数时参数太少因为被调函数sum(int a, int b)中有两个参数,主调函数main()中的sum(x+y)只有一个参数。
而实参应该与形参保证三一致:即顺序一致,类型一致,数量一致。
⑦因为程序中scanf("%d,%d", &a, &b)中两个%d之间有逗号,所以运行程序时输入的两个整数之间必须用逗号隔开,而不是用空格隔开。
[实验任务二]:补充完整程序,灵活掌握C语言中使用函数调用解决问题的方法。
注意:这里提供了以填空的形式出现源程序参考清单,目的是给同学们一个思路。
最好不要将此源程序清单复制到VC++中,否则会出现多处语法错误。
同学们可以据此思路来填写有关语句,从而完成程序。
在调试程序时,一定要运用前面学过的方法。
程序填空实例6-1:下面函数是实现求[1,3000]能被17或23整除的整数的个数。
请将程序补充完整,并调试运行,直到输出正确结果。
将填空后完整的程序以文件名为blank6_1.c保存在实验6文件夹里。
(需要存盘)程序填空实例6-2:编写一函数接受主调函数实参n(这里n==5),并输出如下图形。
n的值通过键盘输入,并由主函数中的语句来由实现。
将填空后完整的程序以文件名为print1.c保存在实验6文件夹里。
(需要存盘)0***0*0*0***0***0*0*0***0【算法提示】:①定义函数printg(),一个形参n,类型为整型,函数无返回值;②找出主、次对角线上‘0’的规律,使用双层循环控制循环n*n次;③循环体内部主、次对角线上打印‘0’,否则打印‘*’;④在主函数中调用函数printg()。
【程序框架】:本程序中main()是主调函数,printg()函数上被调函数。
程序结构形式如下:#include <stdio.h>void printg(int); /* 因为被调函数printg()在主调函数main()之后,需对被调函数声明*/void main ( ){int a;printf("please input a number: \n");scanf("%d", &a);printg(a); /* 在主调函数main()中调用被调函数printg(a) ,其中a为实参*/}void printg(int n){这部分可按照算法提示的①、②、③步补充完整。
相关提示:如果用i控制行标,用j控制列标,则主对角线的规律是:i==j, 即行标等于列标;次对角线的规律是:i+j==n+1,即行标与列标的和值等于方阵的维数+1;}【知识总结】:一般来说,编程时一个问题可以只用一个主函数来处理,但考虑到模块化程序的优越性(主要是大的问题,很小的问题体现不出优越性),所以在实际设计程序时(特别是大的问题),需要设计多个函数(模块),甚至多个文件。
虽然我们碰到的一般是小问题,完全可以用一个主函数来处理,但是我们必须从小问题中学会模块化程序设计的思想和方法,为将来处理大问题打下基础。
程序填空实例6-3:将一个正整数n以相反的顺序输出的递归算法reverse(n)描述如下所示:输出n:当0<=n<=9时;输出n%10,继续输出reverse(n/10):当n>9时据此算法,设计的递归算法如下,请补充完整,并上机调试。
(需要存盘)将补充完整的程序以文件名reverse.c最终保存在实验6文件夹里。
[实验任务三]:掌握函数的嵌套调用和递归调用的程序的执行过程,会使用嵌套调用和递归调用编写程序;编程实例6-1:写一个判断素数的函数,在主函数输入一个整数,输出是否素数的信息。