版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
任务说明
C语言源程序是由函数构成的,而函数又是由语句组成的。因此说语句是完成程序功能的最小单位,而函数则是程序的基本结构单位,即模块,每个模块都可以实现一个特定的功能,因此模块的划分应满足“低耦合、高内聚”。C语言作为一种结构化的程序设计语言,在模块的划分上主要依据是功能。功能独立的函数,或是文件(已封装的功能模块),旨在操作分配占用内存中的数据(常量及变量),进而组成整个程序功能模块。这就是模块化程序设计理念。
对于我们初学编程而言,虽然我们不能迅速实现规模非常大的程序,但是我们可以把程序按照功能划分成模块。在实现代码阶段,这就是一个个的功能模块,我们就可以一个个的编写函数实现其功能。同学们:只要有方法,编程也不是件困难的事!本学习任务将要学习的是深层次理解函数在程序设计思想中扩展的知识,拓展程序设计思路,在编写程序过程中更加灵活地使用函数。
学习函数的拓展知识:带参数的main函数、函数指针、函数的递归调用以及带参数的宏和变量的存储类型和作用域等知识。微课任务说明知识要求理解传给main函数的参数。理解函数指针的知识。掌握函数的递归调用。掌握宏的定义和使用方法。掌握变量的存储类型和作用域知识。能够读懂含有递归调用的程序。能够编写递归函数的程序。能够运用带参数的宏编写程序。能够依据变量的存储类型定义变量。能够调试和排查含有相关内容的程序。能力要求函数的拓展知识011.函数的递归调用(1)函数的嵌套调用C语言的函数定义是互相平行且独立,也就是说,在定义函数,一个函数内不能再定义另一个函数,也就是不能嵌套定义函数,但是可以嵌套调用函数。嵌套调用函数就是在调用的过程中,又调用另一个函数。(2)函数递归调用的定义
函数的递归调用就是在函数嵌套调用中直接或间接的调用自己,参见应用举例10-1中fac函数的定义。(3)用递归方法解决的问题应具备三个条件
可以把要解决的问题转化为一个新问题,而新问题的解决与原来的解法相同,只是所处理的问题有规律的递增或递减;可以应用这个转化过程使问题得到解决;有一个明确的结束递归的判断条件。应用举例10-1
编写计算10!的函数分析:如计算5!,可以通过计算5*4!求得,而计算4!仍可以采用此法,如此递归下去,直到我们已知的1!=1,再依次递推回5的阶乘值。程序代码:#include"stdio.h"intfac(intn){intt;if(n==0||n==1)t=1;elset=n*fac(n-1);//对自身函数的调用,即递归调用。returnt;}voidmain(){printf("10!=%d\n",fac(10));getchar();}请思考:函数的递归调用挺简单,是不是就不用循环了?微课应用举例10-1问题10-1
用递归函数编写一个程序:计算1-100之和的程序,请将代码补充完整。#include"stdio.h"intfun(intn){................................................................................................................................................................}voidmain(){printf("1-100之和=%d\n",fun(100));}问题10-2求以下程序的输出值。#include"stdio.h"intfun(intn){if(n==1||n==2)return1;elsereturnfun(n-1)+fun(n-2);}voidmain(){printf("%d",fun(6));}
输出:................................函数的拓展知识012.传给main函数的参数
带参数main函数的形式为:main(intargc,char**argv)
前者是整型形参,表示命令行中字串的个数,至少为1,后者是指向字符型指针数组的指针,对应多个字串。
当一个C的源程序经过编译、链接后,会生成扩展名为.exe的可执行文件。
因为main()函数不能由其它函数调用和传递参数,所以在操作系统下直接启动运行.exe的可执行文件并传递main()函数的参数。应用举例10-2带参数的main函数
写一个计算阶乘的程序,程序名为“mfac”,编译后生成的可执行文件名为:“mfac.exe”,将文件“mfac.exe”存放在C:\DocumentsandSettings\Administrator目录下,这是Windows系统进入命令提示符状态的默认目录,在“命令提示符”状态下输入:mfac5后按Enter键即可显示结果。(1)mfac文件的内容:#include"stdio.h"#include"stdlib.h"#include"string.h"intfac(intn){intt;if(n==0||n==1)t=1;elset=n*fac(n-1);returnt;}应用举例10-2带参数的main函数voidmain(intargc,char**argv)//这就是带参数的main函数{intn;if(argc!=2||strlen(argv[1])!=1)//确保输入的是文件名和1个字符{printf("输入错误!\n");exit(0);}n=argv[1][0]-‘0’;//将输入的一位数字字符转换为数字printf("%d!=%d\n",n,fac(n));}应用举例10-2:带参数的main函数
(2)编译
编译“mfac”文件,将编译生成的可执行文件“mfac.exe”复制到C:\DocumentsandSettings\Administrator目录下,在“命令提示符”状态下的输入和显示结果如图10-1所示。图10-1在“命令提示符”状态下的输入和显示结果注意:带参数的main函数是在“命令提示符”状态下执行的,程序运行所需要的参数是在执行时连同文件名一起输入的。问题10-3怎样计算10的阶乘?微课应用举例10-2函数的拓展知识013.函数的指针
在C语言中,函数名代表该函数的入口地址,可以定义一种指向函数的指针来存放这种地址。
如double(*fun)(inta,int*p)
表明fun是指向函数的指针变量,定义函数指针要有两对小括号。应用举例10-3
函数指针的应用
以下这段程序,含有两个函数sum和sub,通过函数指针分别调用sum和sub函数,获得两个数的和与差。#include"stdio.h"intsum(intx,inty){returnx+y;}intsub(intx,inty){returnx-y;}//以上定义了两个函数voidmain(){inta,b,c,d,(*p)();//p是函数指针,省略了函数的形参及类型scanf("%d%d",&a,&b);p=sum;//给函数指针赋值c=(*p)(a,b);//通过指针调用函数p=sub;d=(*p)(a,b);printf("a=%d,b=%d,c=%d,d=%d\n",a,b,c,d);getchar();getchar();}程序执行结果:输入:59输出:a=5,b=9,c=14,d=-4变量的作用域和存储域021.变量的作用域
变量的作用域是指程序中的某部分,在这部分中,该变量是有定义的,可以被C编译和连接程序所识别。变量的作用域与其定义语句在程序中出现的位置有直接关系,据此可以划分出局部变量和全局变量。(1)局部变量。局部变量(内部变量)是在函数内部或复合语句内部定义的变量,函数的形参也是局部变量,局部变量的存储类型可以说明成自动类和静态类。
(2)全局变量。全局变量(外部变量)是在函数外部定义的变量。全局变量只能说明成静态存储类型。
2.变量的存储类别C语言中有两种存储类别:自动类和静态类。对应四个说明符:auto(自动);register(寄存器);static(静态);extern(外部)。存储类别确定了所说明对象在内存中的存储位置也确定了其作用域和生存期,这里只介绍常用的auto(自动)和static(静态)存储类别。微课变量的作用域和存储分类变量的作用域和存储域023.局部变量的作用域和生存期(1)自动存储类的局部变量。
在函数内部或复合语句中定义变量时,如缺省存储类型即为auto变量,如我们平时用的inta;就是:autointa;,auto变量的存储单元置于内存的自动存储区,每次进入函数体时,为它分配存储单元,退出时自动释放,再次进入函数体则再次重新分配存储单元,这就是自动局部变量的生存期,因此其作用域是从定义的位置起,到函数结束为止。
使用自动局部变量可以在函数体间形成信息隔离,不同函数中使用了同名变量互不影响,各自所占空间不同。微课局部变量的作用域和生存期应用举例10-4分析以下程序的运行结果。#include"stdio.h"voidfun(inti){ints=0;if(i>0){intn=2;s=s+n;printf("%d\n",s);}}voidmain(){intk;for(k=1;k<3;k++)fun(k);}分析:在以上的fun函数中,有三个局部变量:形参i,自动局部变量s和n。s和i的作用域为fun函数,n的作用域为复合函数内部。三个变量的生存期就是在函数被调用期间,再次调用函数时,三个变量将被重新分配存储空间,变量的值将不被保留,因此两次调用函数输出结果一致都是2。问题10-4请分析原因以下这段程序是对应用举例10-4的改动,编译不通过,请分析原因。#include"stdio.h"voidfun(inti){ints=0;if(i>0){intn=2;}s=s+n;printf("%d\n",s);}voidmain(){intk;for(k=1;k<3;k++)fun(k);}编译不过的原因是:.............................................微课应用举例10-4变量的作用域和存储域02
(2)静态存储类的局部变量。
静态存储类的局部变量是在函数体内用static说明,其作用域仍是函数体内。静态局部变量处在内存的静态存储区中,再次调用函数时不重新分配存储单元,其值一直保留,其生存期是整个程序运行期间,一直延续到不再调用该函数为止。
静态存储类局部变量的初值是在编译时赋予的,如未赋初值自动赋0,这适于编写在函数调用期间必须保留局部变量值的独立函数。应用举例10-5分析以下程序的运行结果。#include"stdio.h"voidfun(inti){staticints=0;//静态存储类if(i>0){intn=2;s=s+n;printf("%d\n",s);}}voidmain(){intk;for(k=1;k<3;k++)fun(k);}分析:与应用举例10-4比较,只是更改了s变量的存储类别,s在生存期内有固定的存储空间,再次调用函数时,s的值是2而不是0,因此程序的输出结果是2和4。微课应用举例10-5变量的作用域和存储域024.全局变量的作用域和生存期
全局变量是在函数外部任意位置定义的,都是静态存储类别,作用域是从变量定义位置开始到整个原文件结束,生存期是整个函数运行期间。
使用全局变量在函数之间开辟了一条数据传递的通道,当全局变量与某函数中的变量同名时,在函数中全局变量被屏蔽(不起作用),全局变量在整个程序运行期间占用内存空间,它在函数外定义,降低了函数的通用性,容易引起副作用,一般不提倡使用全局变量。微课全局变量的作用域和生存期应用举例10-6分析以下程序的运行结果#include"stdio.h"inta=4;//静态全局变量,作用范围是整个程序文件,计作a0intf(intn)//n是形参,局部自动变量,作用范围是f函数{intt=0;//t是局部自动变量,作用范围是f函数staticinta=5;//此a是静态局部变量,作用范围是f函数,计作a1if(n%2){inta=6;t+=a++;}/*此a是动态局部变量,作用范围是本符合语句,计作a2*/else{inta=7;t+=a++;}/*此a是动态局部变量,作用范围是本符合语句,计作a3*/returnt+a++;//此a是a1}voidmain(){ints=a,i=0;//此a是a0,即s=4for(;i<2;i++)s+=f(i);printf("%d\n",s);}应用举例10-6:分析以下程序的运行结果分析:
主函数中s的初值是4,两次调用函数:s=4+f(1)+f(2);f函数中,三处a++,只有returnt+a++;语句中的a++会影响到下一次,即第二次执行函数时a1的值是6,t是自动局部变量,每次执行函数均执行t=0。第一次执行函数,n=1,执行if语句t=6,f(1)的值为6+5是11;第二次执行函数,n=2,执行else语句t=7,f(2)的值为7+6是13;因此,函数执行结果是:28。微课应用举例10-6问题10-5分析以下程序的运行结果#include"stdio.h"int
a=1;int
f(int
c){static
int
a=2;
c=c+1;
return
(a++)+c;}voidmain(){int
i,
k=0;
for(i=0;i<2;i++){int
a=3;
k+=f(a);}k+=a;
printf("%d\n",k);}
执行结果:...............................宏和动态存储分配03C语言中凡以“#”开头的行都称为编译预处理命令行如:#include,,#define,#if,#else,#ifdef等,编译预处理是在C编译程序对源程序进行编译前,由编译预处理程序对这些编译预处理命令行进行处理的过程,必须以#开头不用分号结尾,写在某行的开头,其作用持续到文件的结尾,以#include,#define应用最多,以#define开始的就是宏定义。宏和动态存储分配031.宏
(1)不带参数的宏定义。
形式:#define宏名
宏替换文本
宏名是用户定义的标识符,不能与程序中的其他名字相同,宏名一般使用大写。例:#defineSIZE100
编译时,在此命令行之后,预处理程序对源程序中的所有名为SIZE的标识符用100来换(称为宏替换),切勿认为SIZE等于100。替换文本中可以包含已定义过的宏名,替换文本不能替换双引号中与宏名相同的字串,同一个宏名不能重复定义,应用中,突出一个换字,替换到底再做计算。应用举例10-7写出程序的执行结果#include"stdio.h"#definePI3.14#defineAPIPI+1#defineTPI2*APIvoidmain(){floatx;x=TPI/2;/*→x=2*API/2→x=2*PI+1/2→x=2*3.14+1/2*/printf("TPI/2=%f",x);//不能替换双引号中与宏名相同的字串。}输出为:TPI/2=6.280000
微课应用举例10-7问题10-6分析以下程序的执行结果。#include"stdio.h"#definePI3.14#defineAPI(PI+1)#defineTPI(2*API)voidmain(){floatx;x=TPI/2;//.............................printf("TPI/2=%f",x);//..........................}
输出:...........................................宏和动态存储分配03
(2)带参数的宏定义。
形式:#define宏名(形参表)替换文本
宏名和左括号间无空格,形参之间用逗号隔开,一般替换文本中包含对应的形参。在替换带参数的宏名时,应与宏定义相呼应,有括号,参数个数相同,各参数之间用逗号隔开。最好将整个替换文本和各形参都用括号括起来,不容易有异议。应用举例10-8写出程序的执行结果#include"stdio.h"#defineMU(X,Y)(X)*(Y)voidmain(){inta=2,b;b=36/MU(a,3);//b=36/(a)*(3)printf(“b=36/MU(a,3)=%d\n”,b);//双引号中的内容不换}输出:b=36/MU(a,3)=54
微课应用举例10-8问题10-7分析以下程序的执行结果。#include"stdio.h"#defineMU(X,Y)X*Y........................voidmain(){inta=2,b;b=36/MU(a+1,3);//...........................printf("b=%d\n",b);}输出:............................
注意:宏替换与函数调用有类似之处,宏中对参数无数据类型要求,宏替换不占用程序运行时间,而函数调用则占用。宏和动态存储分配032.动态存储分配
以往用于存储数据的变量和数组都必须在函数的说明部分进行定义,C编译程序通过定义语句了解其所需存储空间的大小,为其分配适当的内存空间,这些空间一经分配在变量或数组的生存期内就是固定不变的,这就是静态存储分配。
动态存储分配是在程序运行期间,需要空间来存储数据时,通过“申请”分配指定的存储空间,当闲置不用时可随时释放,这就是动态存储分配,用标准库函数来实现动态存储分配,与动态存储分配有关的库函数有malloc、calloc和free使用时需包含头文件“stdlib.h”。宏和动态存储分配03
(1)malloc函数。
调用形式:malloc(size)
返回值为:void*或NULL
若没有足够的内存单元分配,函数返回NULL。由于其返回值为空类型,使用时必强制转换成所需要的指针的基类型。
如:int*p;p=(int*)malloc(4);
强制转换成基类型为
int的指针,星号必不可少。动态分配得到的存储单元没有名字,没有确定的初值,只能通过指针引用该存储单元,这是与其它变量的使用不同的。宏和动态存储分配03
(2)free函数。
调用形式:free(p)p是指向由动态存储分配函数malloc分配的地址,函数无返回值,功能是将p所值的存储空间释放。应用举例10-9对动态存储分配单元的使用#include“stdlib.h”//使用动态分配函数应包含的头文件。#include"stdio.h"voidmain(){int*pi;float*pf;//以上定义两个指针变量pi=(int*)malloc(4);/*动态分配4个字节的存储空间,其地址赋给pi*/pf=(float*)malloc(sizeof(float));//所分配存储单元的字节数通过计算得出if(pi!=NULL&&pf!=NULL){*pi=5;//如动态分配成功,再将该存储单元赋值*pf=5.6;printf("%d,%f\n",*pi,*pf);//输出存储单元的值,只能通过指针引用
}free(pi);free(pf);//释放所分配的空间,供系统另做他用}程序输出:5,5.600000
注意:使用动态存储分配,省了对普通变量的定义,必须有对指针变量的定义,动态分配的存储单元必须通过指针才能引用。微课应用举例10-9宏和动态存储分配03
(3)calloc函数。
调用形式:calloc(n,size)n,size都是unsignedint型,返回值为:void*
函数功能是用来给n个同一类型的数据分配连续的存储空间,且系统为这些空间自动赋初值0,分配成功返回首地址,否则返回NULL,可用free函数释放所分配的空间。
应用举例10-10动态存储分配的应用用动态存储分配,接收字符串,将各字符之间添加空格后输出。#include"stdlib.h"#include"stdio.h"voidmain(){char*p,*q;p=q=(char*)calloc(80,sizeof(char));//分配连续的80个存储单元
if(p!=NULL)//如果分配成功
{gets(p);//输入一个字符串存入该空间。
while(*p)//对该串搜索一遍。
{putchar(*p++);//输出一个字符,指针下移一个单元。
putchar('');//输出一个空格。
}}free(q);//释放存储空间。}程序执行结果:输入:abcdefgh输出:abcdefgh微课应用举例10-10
任务实施
任务一
编写递归函数工作内容及要求:
编写递归函数完成以下两个问题的要求。
(1)有5个人坐在一起,第5个人说比第4个人大2岁,第4个人说比第3个人大2岁,第3个人说比第2个人大2岁,第2个人说比第1个人大2岁,第1个人38岁。问第5个人多大年龄?
(2)求Fibonacci数列第18项的值,这个数列有如下特点:第1,2两个数为1,1.从第3个数开始,该数是其前面两个数之和。1123581321…#include"stdio.h"intfun(intn){...................}voidmain(){printf("第5个人的年龄是:%d",fun(5));}输出:............................编程训练10-1-1计算第5个人的年龄#include"stdio.h"intfun(intn){................}voidmain(){printf("第18项的值是:%d",fun(18));}输出:..............................编程训练10-1-2输出Fibonacci数列第18项的值。#include"stdio.h"intfun(intn){.............................}voidmain(){.............................
}程序执行结果:输出:.....................................编程训练10-1-3输出Fibon
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年殡仪馆车辆调度员招聘笔试模拟题
- 2026年中国注册土木工程师考试模拟题
- 小学生感恩教育主题班会2025说课稿
- 初中沟通能力2025说课稿
- 综合复习与评价说课稿2025学年初中信息技术人教版新疆专用七年级下册-人教版新疆专用
- 第三单元 含硅矿物与信息材料说课稿2025学年高中化学苏教版必修1-苏教版2004
- 2026及未来5年快速连接体项目可行性研究报告(市场调查与数据分析)
- 2026年玩偶英语游戏说课稿
- 高中积极情绪说课稿2025
- 催证、审证和改证说课稿2025学年中职专业课-国际贸易实务-国际商务-财经商贸大类
- 金属矿床开采新技术技术
- FBCDZ系列通风机为对旋式防爆主要通风机
- GB/T 37669-2019自动导引车(AGV)在危险生产环境应用的安全规范
- 第四章 AP1000反应堆结构设计(杜圣华)
- 几起重大工程质量安全事故原因
- 初中数学教学大纲
- 设备供货安装方案(通用版)
- 中考物理题型二《开放、推理类题》
- 第二节 金属的腐蚀和防护PPT课件
- 2011年天津市高考物理试卷
- 九年一贯制学校小学初中深度一体化办学策略的调研报告
评论
0/150
提交评论