今天开始尝试改变!
今天要学习函数,一个C语言中的重要组成部分。
首先先聊聊为什么要使用函数?随着学习的深入很多人会发现某段的代码重复使用的几率很大,而如果用一次写一次的话很明显的效率就会比较低,如果有一种方法可以把之前写的相同或者相差不大的代码拿到现在来用的话是不是能提高写代码的效率呢,而且如果出错了纠正的时候也更加的清晰明了。这个时候我们就用到了今天将要学习的内容:函数,它很好的解决了我们想把一段代码多次重复使用的需求。下面让我们看看什么是函数,他的定义是什么。
函数:为了完成某些功能而编写若干行代码的集合。可以供同一个程序或其他程序调用。
函数是C语言的基本组成单位。
函数的优点:代码更加简洁,易于维护,可以提高代码的重用性。
通俗一点理解就是,可以把一段为了实现某种功能的小程序给打包了,打包成一个小包,并加上标签,然后就能随时方便的取用。
函数都在什么时候使用呢?每当写程序的时候重复性的需要实现某种功能的时候就最好用函数了,一个一个写当然也能完成,但是就像前面说的一样效率太低,有省力的方法干嘛不用呢?
使用的时机到了你还要找对使用的地方,以及怎么样去使用它,下面的一系列例子就是关于怎样使用以及使用的地方的一种示例。
函数分为内置函数及自定义函数,自定义函数的方法就是:
返回值类型 函数名称 (参数)
{
//函数体;
返回值;
}
生活案例:做火腿
{
杀猪;
脱毛;
剁肉;
加入淀粉;
加入调味品;
…..
}
[A2]函数名:为函数起一个名称,类似于人名(简单说就为函数起个名称,方便后期调用)
[A3]参数:原材料
[A4]函数体:描述当前函数具体需要完成的功能(简单说当前函数所做的事情)
[A5]返回值:函数最后要想外界输出的结果,返回值要和函数定义的返回类型向对应
C语言中的函数分为内置函数和自定函数
常见的内置函数有:
内置函数 |
头文件 |
用途 |
double sqrt(double x) |
math.h |
计算x的平方根 |
double pow(double x, double y) |
计算x的y次幂 |
|
double ceil(double x) |
求不小于x的最小整数,并以double形式显示 |
|
double floor(double x) |
求不大于x的最大整数,并以double形式显示 |
|
int toupper(int x) |
ctype.h |
如果x为小写字母,则返回对应的大写字母 |
int tolower(int x) |
如果x为大写字母,则返回对应的小写字母 |
|
int rand(void) |
stdlib.h |
产生一个随机数 |
void exit(int retval) |
终止程序 |
小示例,需要记住一个知识点,计算机中的元年,这个元年的具体时间是1970-01-01 00:00:00.直接随机的数字称为伪随机数,因为使用的相同的随机种子,如果加入另一个变量如当前时间距离元年的秒或分钟数将会生成真正的随机数.
//计算1~10平方根和立方 int i; double square,power; for(i=1;i<=10;i++){ square = sqrt(i);//使用sqrt(x)函数计算x平方根 power = pow(i,3);//使用pow(x,y)函数计算x的y次方 printf("%d的平方根是%.2lf,立方是%.2lf\n",i,square,power);//.2lf:double类型精确到小数点后两位 } //floor()和ceil()函数 printf("---------floor()函数------------\n");//floor(x);--->不大于x的最大整数,不会四舍五入 printf("floor(12.1)=%f\n",floor(12.1));//12 printf("floor(-12.1)=%f\n",floor(-12.1));//-13 printf("floor(12.8)=%f\n",floor(12.8));//12 printf("floor(-12.8)=%f\n",floor(-12.8));//-13 printf("---------ceil()函数------------\n");//ceil(x);--->不小于x的最小整数,不会四舍五 q入 printf("ceil(12.1)=%f\n",ceil(12.1));//13 printf("ceil(-12.1)=%f\n",ceil(-12.1));//-12 printf("ceil(12.8)=%f\n",ceil(12.8));//13 printf("ceil(-12.8)=%f\n",ceil(-12.8));//-12 //获取随机数 srand((unsigned)time(NULL)); //设置随机种子,time(NULL):获取当时间距1970-01-01 00:00:00的秒数 for(i=0;i<10;i++){ // printf("%d\t",rand());//rand():伪随机数;产生的随机数0~32767之间 //产生一个0~99之间的随机数 printf("%d\t",rand()%100); } |
示例2:使用随机实现人机猜拳大战
int userCount=0;//统计用户获胜的次数 int computerCount=0;//统计电脑获胜的次数 int user,computer;//用于保存用户或电脑出的拳 char isContinue;//是否继续 srand((unsigned)time(NULL)); //人机猜拳大战 (0:剪刀,1:石头,2:布) y do{ printf("***********************************\n"); printf("**********人机猜拳大战*************\n"); printf("***********************************\n"); computer = rand()%3; //产生0,1,2的随机数 printf("请出拳:0代表剪刀,1代表石头,2代表布\n"); scanf("%d",&user); //判断比赛结果: 人胜:(user==0&&computer==2||user==1&&computer==0||user==2&&computer==1) if((user==0&&computer==2)||(user==1&&computer==0)||(user==2&&computer==1)){ printf("恭喜你赢了~~~~~~~~~~~~~~~~~~\n"); userCount++; }else if(user==computer){ printf("平局,再来一次~~~~~~~~~~~~~~~~~~\n"); }else{ printf("对不起,你输了~~~~~~~~~~~~~~~~~~\n"); computerCount++; } printf("是否继续与电脑决战到天亮? y代表继续,n代表是退出\n"); fflush(stdin);//刷新(清空)缓冲区 isContinue=getchar();//获取输入的字符 }while(isContinue=='y');
printf("您赢了%d次,电脑胜了%d次\n",userCount,computerCount); if(userCount>computerCount){ printf("经过您的不懈努力,终于战胜了电脑!\n"); }else if(userCount==computerCount){ printf("你和电脑旗鼓相当,继续加油!\n"); }else{ printf("你被电脑打败了,继续加油!\n"); } |
上面是内置的别人写好的下面是自己自定义函数的方法.
自定义函数:
{
//函数体;
返回值;[A4]
}
[A1]返回值类型:如果无返回类型void,如果有返回值类型(int,double,float,short,long,char..)
C语言中的函数至多可以返回一个值,不能返回多个值;
返回值的数据类型必须与函数原型中返回值的数据类型匹配;
当遇到 return 语句时,函数执行将终止。程序控制流将立即返回调用函数;
[A2]函数名必须满足命名规则,与变量名命名规则类似.
[A3]形式参数(形参):数据类型 变量名,调用时具体传入的值为实际参数(实参),实参的类型,数量,顺序必须与形参相对于。形参是函数局部变量,只在该函数内部有效
[A4]其函数的返回值必须与返回值类型相匹配,如果你声明的是一有返回值的函数,但没有使用return语句,将报错.
示例:
//有返回值,有参数 a和b为形式参数(形参) int max(int a,int b[A1] ){ int m; if(a>b){ m=a; }else{ m=b; } return m; } |
调用: int m = max(2,3[A2] );//实际参数 |
[A1]形参:形式参数,标明了需要的数值类型和数量.
[A2]实参:实际参数,要与行参的类型,数量,顺序相对应,一模一样.
C语言调用自定义函数时要先在main函数上面声明头文件.调用函数原型说明在形式上与函数头部类似,最后加一个分号。原型说明中参数表里的参数名可以不写(只写参数类型)。
函数的调用,声明完头文件以后在main函数里面直接使用函数名就可以完成调用,程序会自动转到相应的函数体中运算.
示例:
#include <stdio.h> //函数原形定义 void juxing();//计算矩形的面积 void sanjiaoxing();//计算三角形的面积 [A1] void main(){ //根据用户输入的代码(0代表矩形,1代表三角形,2代表圆)计算其面积 int code; printf("请输入图形代码:0代表矩形,1代表三角形,2代表圆"); scanf("%d",&code); if(code==0){ juxing();[A2] //通过函数名调用 }else if(code==1){ sanjiaoxing();[A3] } }
//计算矩形的面积 void juxing(){ int length,width,s; printf("请输入矩形的长\n"); scanf("%d",&length); printf("请输入矩形的宽\n"); scanf("%d",&width); if(length>0&&width>0){ s=length*width; printf("矩形的面积为%d\n",s); }else{ printf("您输入有误!长和宽必须大于零!\n"); } } //计算三角形的面积 void sanjiaoxing(){ int bottom,height; float s; printf("请输入三角的底\n"); scanf("%d",&bottom); printf("请输入三角形的高\n"); scanf("%d",&height); if(bottom>0&&height>0){ s=bottom*height/2; printf("三角形的面积为%f\n",s); }else{ printf("您输入有误!底和高必须大于零!\n"); } } |
[A1]函数原形
[A2]函数调用:将执行被调用函数中代码
[A3]函数调用
作业1:编写一个函数void isTri(),判定用户输入的三个边长是否能组成三角形。三角形的两个组成条件是:
1.三边都要大于0
2.任意两边之和大于第三边
void isTri();//三个边长是否能组成三角形 void main(){ isTri();//调用 } //判断是否能组成三角形的函数 void isTri() { int a,b,c; printf("请输入三角形的边长1:\n"); scanf("%d",&a); printf("请输入三角形的边长2:\n"); scanf("%d",&b); printf("请输入三角形的边长3:\n"); scanf("%d",&c); //判断三边边长是否都大于0 if(a>0&&b>0&&c>0){ //任意两边之和大于第三边 if((a+b>c)&&(a+c>b)&&(b+c>a)){ printf("%d,%d,%d能组成三角形\n",a,b,c); }else{ printf("您输入的边长不满足任意两边之和大于第三边的条件\n"); } }else{ printf("您输入的边长有误,边长必须为正数!\n"); }
作业2:编写一个函数int pieAdd(int n),计算1+2+3+……+n的值并返回。比如pieAdd(3)的返回值是1+2+3=6
int pieAdd(int n);//计算从1~N累加和的程序 void main(){ int sum = pieAdd(5);//5实参要形参相对于(类型,数量,顺序) printf("累加为:%d\n",sum); } int pieAdd(int n){ int i,sum=0; for(i=1;i<=n;i++){ sum+=i; } return sum;//返回值要与返回值类型向对应 }
比如:1634=1^4+6^4+3^4+4^4作业3:写一个函数void rose(int n),判断某一个四位数是不是玫瑰花数(所谓玫瑰花数即该四位数各位数字的四次方和恰好等于该数本身。
void rose(int n);//判断N是否为玫瑰花数 void main() { rose(1634);//函数调用 } void rose(int n){ int ge,shi,bai,qian,sum; //获取个位 //1234===>1234%10==>4 ge=n%10; //获取十位 //1234==>1234/10==>123%10==>3 shi=n/10%10; //获取百位 //1234==>1234/10==>123/10==>12%10==>2 bai=n/10/10%10; //获取千位 //1234/10==>123/10==>12/10==>1 qian=n/1000; sum=pow(ge,4)+pow(shi,4)+pow(bai,4)+pow(qian,4); if(sum==n){ printf("%d是一个玫瑰花数\n",n); }else{ printf("%d不是一个玫瑰花数\n",n); } }
函数的嵌套调用,在一个函数里面调用另一个函数,要记住声明时应把所有调用的函数的原型都声明一下.
函数的递归调用:函数自身调用自身。
示例:使用递归实现计算N的阶乘
#include <stdio.h> int factorinal(int a);//函数递归调用实现计算阶乘 void main() { int sum = factorinal(5); printf("5的阶乘为%d",sum); } //计算a的阶乘 int factorinal(int a) { if(a==1){ return 1; }else{ return a*factorinal(a-1); } }
利用递归实现斐波那契数列: 1 1 2 3 5 8 13 21....
跟菲波那切数列有关的一个古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月,后每个月又生一对兔子,假如兔子都不死,1年后总共有多少对兔子?
根据规律得出公式:f(n)=f(n-1)+f(n-2); n>2
#include <stdio.h> int fibonacii(int n);//斐波那契数列 void main() { int num = fibonacii(12); printf("1年后共有%d对兔子",num); } int fibonacii(int n){ if(n==1||n==2){ return 1; }else{ return fibonacii(n-1)+fibonacii(n-2); } }
变量:程序中变量不同的使用范围,称为变量的作用域。变量的作用域决定变量的可访问性.出了作用域以后不在有效.程序中我们声明了很多的变量,下面我们要知道的是变量是有其作用范围的,变量分为全局变量和局部变量,全局变量如同国家主席,在一个国家里到哪刷脸都好用,而
局部变量:在函数内声明的变量,其作用范围仅限于该函数内
1.主函数中定义的变量也只能在主函数中使用,不能在其它
函数中使用。
2.允许在不同的函数中使用相同的变量名,它们代表不同的
变量,分配不同的存放单元,互不相干,不会发生混淆。
3.复合语句中定义的变量,也是复合语句的局部变量。所谓
复合语句,就是用{}包含起来的语句块。
#include <stdio.h> void m(); void main() { int a=1,b=2; { int a=3,b=4;//这个的作用域就只在这个main函数中, printf("复合语句的变量a=%d,b=%d\n",a,b);//打印出的结果也就是在这个函数中赋值的1,2 } printf("main函数的变量a=%d,b=%d\n",a,b); m(); } void m() { int a=5,b=6; printf("m函数的变量a=%d,b=%d\n",a,b);//虽然同样是变量a,b此处打印的就是5,6 }
1.全局变量定义必须在所有的函数之外。包括main函数.
2.全局变量可加强函数模块之间的数据联系, 但是又使函数要依赖这些变量,因而使得函数的独立性降低。
3. 在同一源文件中,允许全局变量和局部变量同名。在局部变量的作用域内,同名的全局变量不起作用。
#include <stdio.h> int sum=0;//全局变量 void addNumbers() { int sum;//局部变量 int num1,num2; printf("\n 请输入两个数:"); scanf("%d %d",&num1,&num2); sum=num1+num2; printf(" 子函数中 sum 的值是 %d \n",sum); } void main() { int sum=0;//局部变量 addNumbers(); printf("\n 主函数中 sum 的值是 %d \n ",sum); }
上面的就是一个全局变量的示例其打印的结果根据输入的数值的不同,第一次打印的变量sum的变量是在不停变动的,二第二次打印的sum则始终为0
小练习:输入一个数字计算阶乘;
#include <stdio.h> int fun(int n); void main(){ int n; printf("请输入您要计算阶乘的数:\n"); scanf("%d",&n); int sum=fun(n); printf("%d的阶乘是%d",n,sum); } //计算阶乘 int fun(int n){ int sum=1; while(n>1){ sum*=n; n--; } return sum; }
小练习:大赛评分计算,10为评为为选手打分,去掉一个最高分和一个最低分,计算选手的最后得分。
#include <stdio.h> void showMenu(); void getScores(); float calcAvg(); float scores[10];//定义全局变量,用于保存评委的打分 void main(){ float avg; //1.打印菜单 showMenu(); //2.获取评委打分 getScores(); //3.计算选手最后得分 avg = calcAvg(); printf("该选手去掉一个最高分和一个最低分最终得分为%.2f分\n",avg); } //1.打印菜单 void showMenu() { printf("************************************************\n"); printf("*************郑州尚学堂杯博客大赛***************\n"); printf("************************************************\n"); } //2.获取10个评委打分 void getScores() { int i; for(i=0;i<10;i++){ printf("请%d号评委打分:\n",i+1); scanf("%f",&scores[i]);//将评委的打分获取并保存到数组中 } printf("评委打分完毕,分数正在紧张统计中.....\n"); } //3.统计评委成绩去掉一个最高分和一个最低分,计算选手平均得分 float calcAvg() { float max,min,avg,sum=0; int i; max=scores[0];//假设第一个分数最高 min=scores[0];//假设第一个分数最低 for(i=0;i<10;i++){//计算总分 sum+=scores[i]; if(scores[i]>max){//获取最高分 max=scores[i]; } if(scores[i]<min){//获取最低分 min=scores[i]; } } //去除最低分和最高分计算平均分 avg=(sum-max-min)/8; return avg; }
再啰嗦总结一下,什么是函数?函数就是一个为了实现某些功能的代码的一个集合,或者说是把实现某些功能的代码集合打包起来加了个标签(名字),这个带标签的代码集合就是函数,它的作用和定义下不多,就是可以把相对独立的某个功能抽离出来,使之成为程序中的一个独立个体,可以方便在一个程序或其他程序中重复使用.由此也就可以明白了,只要你需要重复实现某个功能的话就可以把它做好以后抽离出来打包好价格标签留着需要的时候拿出来用.这就是函数对于我们的作用.
#include <stdio.h> void m(); void main() { int a=1,b=2; { int a=3,b=4; printf("复合语句的变量a=%d,b=%d\n",a,b); } printf("main函数的变量a=%d,b=%d\n",a,b); m(); }
void m() { int a=5,b=6; printf("m函数的变量a=%d,b=%d\n",a,b); } |