if(m==1||m==3||m==5||m==7||m==8||m==10||m==12)
n_31++;/*统计31天的月份个数*/
else
if(m==4||m==6||m==9||m==11)
n_30++;/*统计30天的月份个数*/
x=31*n_31+30*n_30+day;/*算一下除去2月份的天数*/
if(month>2)
if(isleap(year)==1)/*利用leap函数判断year是否是闰年*/
x=x+29;/*闰年,统计进2月份天数为29天*/
else
x=x+28;/*平年,统计进2月份天数为28天*/
printf("它是第%d天\n",x);
getch();}
【相关知识】
1.函数的基本概念
C程序中有一个函数是必须存在的,这个函数就是main函数(又称为主函数)。
main函数是唯一的。
main函数是C程序执行的入口,即程序开始执行时,系统首先调用main函数执行。
C程序中所有函数的定义是平行的,函数之间不存在嵌套或从属的关系,但是函数之间可以相互调用。
除main函数不能被其他函数调用外,其他函数是一个可以反复使用的程序段。
函数是通过被调用而执行的。
例如在本程序中,主函数调用用户自定义函数isleap。
用户自定义函数必须定义后才能使用。
2.函数定义的一般形式
函数定义的一般形式如下:
类型标识符函数名(形式参数表列)
{声明部分
执行部分}
在实例中,用户自定义函数为isleap(),该用户自定义函数的返回类型是整型,形式参数year是整型。
{}内的内容称为“函数体”。
函数的定义,有几点需要说明:
(1)函数名前面的类型标识符用来说明函数返回值的类型,函数返回值通过return语句得到。
若函数无返回值,可省略这一部分,或用类型标识符“void”表示。
例如在本例题中函数返回return
(1);
Ø
(2)函数名要符合标识符的命名规则。
Ø(3)函数定义时的参数称为形式参数,简称形参。
形式参数列表说明的是函数间要传递的数据。
调用函数与被调用函数之间的数据传递就是依靠形式参数在调用时接收数据来完成的。
形式参数列表由各个参数的名字和类型说明组成。
形参列表中若有多个形参,则形参之间用逗号分隔。
(4)如果在形式参数列表中只列出参数名,则需要在其后说明每个参数的类型。
3.函数返回值
函数一般都是要返回值,它使用return语句将函数值带回到调用处。
return语句格式为:
return(<表达式>);
return语句有两个功能:
(1)return语句将表达式的计算结果返回给调用函数。
(2)结束return语句所在函数的执行,返回到调用该函数的函数中继续执行。
函数返回值的类型应为定义函数时的函数值类型。
若函数值类型与return语句中表达式值的类型不一致,则以函数值类型为准进行类型转换。
【课堂精练】
1.定义函数fun计算:
m=1-2+3-4+…+9-10的值,程序运行结果如图7-2所示。
图7-2程序运行结果
根据程序运行结果,请将下面程序补充完整并调试。
#include"stdio.h"
intfun(intn)
{intm=0,f=1,i;
for(i=1;i<=n;i++)
{m=m+i*f;
_________________________}
returnm;}
main()
{printf("m=%d\n",fun(10));
getch();}
2.输入两个双精度的值,通过编写函数,求出最大值。
程序运行结果如图7-3所示。
图7-3程序运行结果
根据程序运行结果,请将下面程序补充完整并调试。
#include"stdio.h"
doublemax(doublea,doubleb)
{return(a>b?
a:
b);}/*引用条件运算符*/
main()
{doublex,y,temp;
printf("请输入两个变量的值:
");
scanf("%lf%lf",&x,&y);
_______________________/*函数返回值赋给变量temp*/
printf("\n最大值为:
%1f\n",temp);
getch();}
7.2函数的调用
【学习目标】
(1)掌握函数的几种调用方式
(2)掌握函数说明的方法
(3)掌握函数的几种参数情况
实例25函数的调用——求两个整数之和
【实例任务】
从键盘上任意输入两个整数,求其和,运行结果如图7-4所示。
图7-4程序运行结果
【程序代码】
#include"stdio.h"
#include"stdlib.h"
voidstart_information()/*自定义函数,不返回值,输出提示信息*/
{
printf("程序开始!
\n");
}
intsum(intx1,intx2)/*定义函数的返回值类型,函数名,形参*/
{ints;
s=x1+x2;/*计算x1和x2之和,放到s中*/
return(s);/*return语句回运算结果*/
}
voidend_information()
{
printf("程序结束!
\n");
}
main()
{intx,y,z,s;
start_information();/*调用不返回值的函数,输出一行提示信息*/
printf("请输入x和y的值:
");
scanf("%d%d",&x,&y);
s=sum(x,y);/*调用函数,返回值赋给s变量*/
printf("二者的和值为:
%d\n",s);
end_information();/*调用函数,输出一行提示信息*/
getch();
}
【相关知识】
1.函数调用前提
在C程序中,一个函数可以被调用,但要求这个函数已存在,或者函数是系统函数,或者函数是用户已定义完成的函数。
对于库函数,只要在调用函数所在文件用include命令包含相应的头文件即可;而对于用户定义的函数,调用时函数已经被定义。
如果未定义,需在调用前添加函数说明。
2.函数的调用
函数有两种情况,一种是有返回值的函数,一种是只完成一定的操作,不返回值。
对于返回值,函数的调用形式是:
变量=函数名([实参列表]);
对于不返回值的函数,调用形式是:
函数名([实参列表]);
调用函数时,还有几点需要说明:
Ø
(1)调用函数时的参数称为实际参数,简称实参。
实参可以是变量、常量或表达式,是有确定值的参数。
在本程序中,主函数中“p=product(a,b);”语句中,a和b都是实参。
Ø
(2)函数的形参与实参要求个数相等,并且对应的形参和实参的类型相同。
若被调函数是无参函数,则实参表列为空。
在本程序中,定义“intproduct(intx,inty)”中,x和y是形式参数,且均为整型数据;而在主函数调用表达式“p=product(a,b)”中,a和b都是实参,且均为整型数据。
Ø(3)数据传递是通过形参接收实参的数值完成的。
函数调用时,形参被分配内存单元,并接收对应实参传来的值。
在本例题中,数据传递是实参值传递给形参值,a值传递给x值,b值传递给y值。
(4)调用函数时,当实参个数多于一个时,用逗号让各参数彼此分隔开。
3.函数说明
C语言中,函数和变量一样,都要先定义后引用。
如果在函数调用前没有定义函数,则需在调用函数前进行函数说明。
函数说明的形式为:
类型名函数名(参数类型1[参数名1],…,参数类型n[参数名n])
实例中,end_information()函数,属先引用后定义,须添加函数说明。
在函数说明中,函数的类型名要与函数返回值的类型一致。
如果没有函数说明,则隐含此函数返回值为int类型。
实例26函数的参数形式——求1!
+2!
+3!
+…+n!
的值
【实例任务】
从键盘上输入n的值,然后求1!
+2!
+3!
+…+n!
的值。
程序的运行结果如图7-5所示。
图7-5程序运行结果
【程序代码】
#include"stdio.h"
#include"stdlib.h"
longf(intn)/*f函数的功能用来实现n!
*/
{inti;
longs;
s=1;
for(i=1;i<=n;i++)
s=s*i;
returns;}
main()
{longs;
intk,n;
printf("请输入n的值为:
");
scanf("%d",&n);
s=0;
for(k=0;k<=n;k++)
s=s+f(k);/*调用自定义函数,返回值直接与a相加*/
printf("\n1!
+2!
+…+%d!
的值为:
%ld\n",n,s);
getch();}
【相关知识】
1.函数间参数的传递
C语言中,函数的实参和形参数之间的数据传递是单方向的值传递方式。
在函数调用时,使用变量、常量或数组元素作为函数参数时,将实参的值复制到形参相应的存储单元中,即形参和实参分别占用不同存储单元,这种传递方式称为“值传递”。
值传递的特点是单向传递,即只能把实参的值传递给形参,而形参值的任何变化都不会影响实参。
在本例题的主函数中,语句s=s+f(k),其中k是实参;而用户自定义函数“longf(intn)”中,n是形参。
在“值传递”的过程中,k的值传递给n;而n的值不能传递给k,这种传递是单向值传递。
在参数传递时,参数的类型和参数的个数要一一对应。
2.形参的生命周期
在调用函数时,系统给形参分配内存单元,将实参的值赋给形参。
函数执行完后,形参占用的空间被释放,实参仍保留调用前的值。
【课堂精练】
1.从键盘上任意输入两个整数,求其积,运行结果如图7-6所示。
图7-6程序运行结果
根据程序运行结果,请将下面程序补充完整并调试。
#include"stdio.h"
#include"stdlib.h"
intproduct(intx,inty);/*函数product的声明语句*/
intmain()
{inta,b,p;
printf("请输入变量a和b的值:
");
scanf("%d,%d",&a,&b);
_____________________/*调用函数product*/
printf("\na和b的乘积是:
%d",p);
getch();}
intproduct(intx,inty)/*计算两个整数的积*/
{ints;
_____________________
return(s);}
2.定义函数求x的平方值和xn值,然后调用两个函数。
程序的运行结果如图7-7所示。
图7-7程序的运行结果
根据程序的运行结果,将下面程序补充完整并调试。
#include"stdio.h"
intsqure(intj);/*函数说明*/
doublepower(doublex,intn);/*函数说明*/
main()
{intj=4;
putchar('\n');
printf("4的平方值为:
%d\n",squre(j));/*输出项为调用函数返回的值*/
printf("3.0的4次方值为:
%f\n",____________________________);
getch();}
intsqure(intj)/*定义函数,求j的平方*/
{returnj*j;}
doublepower(doublex,intn)/*定义函数,求x的n次方*/
{doublep;
if(n>0)
for(p=1.0;n>0;n--)
_______________________________/*将x的值乘n次,并存放到p中*/
else
p=1.0;/*如果传递的n值小于0,则p=1.0*/
return(p);}/*将p的值返回到函数调用处*/
7.3函数的嵌套与递归调用
【学习目标】
(1)掌握函数的嵌套调用方法
(2)理解函数的递归调用方法
实例27函数的嵌套调用——编程计算(1!
)2+(2!
)2+(3!
)2+(4!
)2+(5!
)2的值
【实例任务】
编程计算(1!
)2+(2!
)2+(3!
)2+(4!
)2+(5!
)2的值,运行结果如图7-8所示。
图7-8程序运行结果
【程序代码】
#include"stdio.h"
#include"stdlib.h"
longf1(intp)
{intk;
longr;
longf2(int);/*f1中调用自定义函数f2,实现了嵌套调用*/
r=f2(p);/*调用f2,来计算p的阶乘*/
returnr*r;}/*返回阶乘的平方*/
longf2(intq)/*计算阶乘的函数*/
{longc=1;
inti;
for(i=1;i<=q;i++)
c=c*i;
returnc;}
main()
{inti;
longs=0;
for(i=1;i<=5;i++)
s=s+f1(i);/*主函数调用f1函数*/
printf("此表达式的值为:
%ld\n",s);
getch();}
【相关知识】
1.函数的嵌套调用
C语言中不允许嵌套的函数定义,各函数之间是平行的,不存在上一级函数和下一级函数的问题。
但是C语言允许在一个函数的定义中出现对另一个函数的调用。
这样就出现了函数的嵌套调用,即在被调函数中又调用其他函数。
在本例题中,用户自定义函数f1和f2,f1函数调用f2函数,它们之间是平行的。
2.函数的嵌套调用执行过程
函数的嵌套调用可以用如图7-9的调用形式表示。
图7-9函数嵌套调用的图形表示
从上面可以明显看出其执行过程是:
执行main函数中调用a函数的语句时,即转去执行a函数;在a函数中调用b函数时,又转去执行b函数;b函数执行完毕返回a函数的断点处继续执行,a函数执行完毕返回main函数的断点处继续执行。
实例28函数的递归调用——求n!
【实例任务】
求n!
问题,运行结果如图7-10所示。
图7-10程序运行结果
【程序代码】
#include"stdio.h"
#include"stdlib.h"
fact(intn)
{intt;
if(n==1||n==0)
t=1;
else
t=n*fact(n-1);
returnt;}
main()
{intn,t;
printf("请输入n的值:
");
scanf("%d",&n);
if(n<0)
printf("输入数据错误!
\n");
else
t=fact(n);
printf("\n%d!
=%d\n",n,t);
getch();}
【相关知识】
1.递归调用的概念
一个函数在它的函数体内调用它自身称为递归调用,这种函数称为递归函数。
C语言允许函数的递归调用。
在递归调用中,主调函数又是被调函数。
执行递归函数将反复调用其自身。
每调用一次就进入新的一层。
实例中,可以将n阶问题转化成n-1的问题,即f(n)=n*f(n-1),这就是递归表达式。
由以上表达式可以看出:
当n>1时,求n!
可以转化为求解n×(n-1)!
的新问题,而求解(n-1)!
与原来求n!
的方法完全相同,只是所处理对象在递减1,由n变成了(n-1)。
以此类推,求(n-1)!
的问题又可转化为(n-1)(n-2)!
的问题,直至所处理对象的值减至0(即n=0)时,阶乘的值为1,递归结束不再进行下去,至此,求n!
的这个递归算法结束。
总之,上面的公式说明了每一循环的结果都有赖于上一循环的结果,递归总有一个“结束条件”,如n!
的结束条件为n=0。
2.递归调用的过程
在函数的递归调用中,一个重要问题是:
当函数自己调用自己时,要保证当前函数中变量的值不丢失,以便在返回时保证程序的正确性。
在递归调用时,系统将自动把函数中当前变量的值保留下来,在新的一轮调用过程中,系统为该次调用的函数所用到的变量和形参另开辟存储单元。
因此,递归调用的层次越多,同名变量(即每次递归调用时当前变量)所占用的存储单元也就越多。
当最后一次函数调用运行结束时,系统将逐层释放调用时所占用的存储单元。
每次释放本次所调用的存储单元时,程序的执行流程就返回到上一层的调用点。
同时取用当时调用函数进入该层时函数中的变量和形参所占用的存储单元中的数据。
实例中,对于fact函数中的调用语句t=n*fact(n-1),当n=5时,其递归调用过程如下。
递归级别执行操作
0fact(5)
1fact(4)
2fact(3)
3fact
(2)
4fact
(1)
4返回1fact
(1)
3返回2fact
(2)
2返回6fact(3)
1返回24fact(4)
0返回120fact(5)
3.函数的递归调用有两种形式。
函数的递归调用有两种形式,一种是直接递归调用,即一个函数可直接调用该函数本身,如:
floatfunc(intn)
{intm;
floatf;
f=func(m);}
另一种是间接递归调用,即一个函数可间接地调用该函数本身,如:
funcl(intn)func2(intx)
{intm;{inty;
func2(m);}func1(y);}
【课堂精练】
1.求n!
。
程序的运行结果如图7-11所示。
图7-11程序运行结果
根据程序的运行结果,将下面程序补充完整并调试。
#include"stdio.h"
intfun(intn)
{if(n>0)
returnn*fun(n-1);/*函数自身调用,即递归调用*/
else
return1;}
main()
{inta,div;
printf("请输入整数的值:
\n");
scanf("%d",&a);
_____________________________;/*调用自定义函数*/
printf("a=%d\n",div);
getch();
}
2.编制一递归函数,将一个十进制正整数(如:
15613)转换成八进制数形式输出。
该编程的思路:
十进制整数转换成八进制整数的方法是除8逆向取余。
十进制转换成八进制的过程如下所示:
余数:
商:
15613%8=515613/8=1951
1951%8=71951/8=243
243%8=3243/8=30
30%8=630/8=3
3%8=33/8=0
结果:
36375
该递归算法描述如下:
①先求出余数m:
m=x%8;
②求x除以8取余后的整数商:
x=x/8;
③如果x不等于0,递归调用该函数,否则执行④。
④输出余数m。
⑤返回调用点。
程序的运行结果如图7-12所示。
图7-12程序运行结果
根据程序的运行结果,将下面程序补充完整并调试。
#include"stdio.h"
#include"stdlib.h"
voiddtoo(intx)
{intm;
m=x%8;/*相除取余数*/
x=x/8;/*相除取商*/
if(x!
=0)
_____________________/*递归调用自定义函数*/
printf("%d",m);}
main()
{intn;
printf("请输入十进制的数为:
");
scanf("%d",&n);
printf("\n该十进制数%d所对应的八进制数为:
",n);
_______________________/*调用自定义函数*/
getch();}
7.4函数中标识符的作用域与存储类
【学习目标】
(1)了解函数中标识符的作用域
(2)了解函数中标识符的存储类
实例29函数中标识符的作用域——初识局部变量与全局变量
【实例任务】
通过程序初识局部变量与全局变量。
运行结果如图7-13所示。
图7-13程序运行结果
【程序代码】
#include"stdio.h"
#include"stdlib.h"
inta=1;/*定义全局变量a,并赋初值,在下面函数中均有效*/
intfunc(intx,inty)
{return(x*y);}
intb;/*定义全局变量b*/
main()
{intc;/*定义局部变量,只在main函数内有效*/
b=2;
c=func(a,b);
printf("三个变量的值分别为:
\n");
printf("a=%d,b=%d,c=%d",a,b,c);
getch();}
【相关知识】
1.局部变量
在一个函数内部定义的变量是内部变量,它只能在本函数范围内有效,即它只有在本函数内才能使用它们,在此函数以外是不能使用这些变量的,这样的变量也称为是“局部变量”。
另外,形式参数也是局部变量。
2.全局变量
一个源文件可以包含一个或若干个函数。
在函数内定义的变量是局部变量,而在函数之外定义的变量称为全局变量。
全局变量可以为本文件中其他函数所共用。
它的有效范围为从定义变量的位置开始到本源文件结束。
实例中有语句“inta=1,b=2;”,其中a、b是全局变量。
实例30函数中标识符的