第五章 函数
首先恭喜你已经学到了函数这一部分,,革命尚未成功,同志仍需努力。我真心的希望你能戒骄戒躁,稳扎稳打,去突破如今的桎梏,找到自己一生所热爱的事物,加油加油橘猫
文章目录
1.为什么要用函数
- 避免代码冗长
- 模块化的设计思路
- 按功能划分,每个函数代表一个功能,而函数的名字要体现函数的功能含义,类似变量标识符
y=f(x)
2.函数要先定义再使用,和变量一个道理
定义:抓住三要素!牢牢记住!!!!!!!!!
- 函数名————-体现功能
- 参数列表——-比如y=f(x),,,x就是参数 比如z=f(x,y),,x,y就是参数(参数的个数根据需求自行定义)
- 返回值——还比如y=f(x),,,y是函数根据x的值和f的功能执行后的结果
函数体————执行什么样的功能,涉及的处理代码叫做函数体
3.函数的定义与调用
1.定义无参数的函数
#include <stdio.h>
void printfwelcome(){
printf("====================\n");
printf("欢迎来到我的程序\n");
printf("====================\n");
}
//1.函数调用时,要注意是怎么调用的,,函数名要一致,数据类型不要写(定义的时候才用)
int main(){
printfwelcome();//在运行到这个函数的时候会跳回上面定义的函数
return 0;
}
2.定义有参数有返回值的函数
如y=f(x),,一个返回值,一个参数
#include <stdio.h> /******一个参数,带着一个返回值,这个返回值是个整型,所以用int*************/ int getDataFormX(int x) //形式参数,需要包含变量名(),变量类型 { //x变量名是可以随意随意起的 int data; data = x-1; return data; /*还有一种写法,直接就是一个返回值*/ // return x-1; } /*********在这整个过程中我们关心的只有值和数据的传递*********/ int main(){ int x; int y; puts("请输入一个数:"); scanf("%d",&x); //首先你输入的x的值 y = getDataFormX(x);//然后这个里面的x的值,会传给上面定义的函数里面的变量,,他们是值的传递,地址空间不一样 //在定义的函数里面一顿操作之后,会返回一个数,这个数在传回来给到现在的 y; printf("x =%d,y =%d",x,y); return 0; }
一个返回值,两个参数
#include <stdio.h>
/*****自己定义的函数*****/
int add(int a,int b)//两个数据,,2参数,
{
int c;
c = a+b;
return c;
}
/*******主函数********/
int main(){
int x,y,z;
puts("请输入一个数:");
scanf("%d",&x);
puts("请再输入一个数:");
scanf("%d",&y);
//x,y两个数据值传给上面定义的函数,,在定义函数里面定义两个数据类型来承接过来的数据,,返回一个值回来,给到z
z =add(x,y);//--------要注意x,y是用来传递数值的变量,,上面已经定义过,所以不要加数据类型,易错点
printf("%d+%d=%d",x,y,z);
return 0;
}
- 一个返回值,三个参数,多个参数可以以此类推
#include <stdio.h>
/*****自己定义的函数*****/
//三要素:返回值,参数列表,功能
int add(int a,int b,int z) //函数原型
{
int c;
c = a+b+z;
return c;
}
/*******主函数********/
int main(){
int x,y,z,ret;
puts("请输入一个数:");
scanf("%d",x);
puts("请再输入一个数:");
scanf("%d",y);
puts("请再输入一个数:");
scanf("%d",z);
ret =add(x,y,z);
printf("%d+%d+%d=%d",x,y,z,ret);
return 0;
}
3.定义空函数
程序设计,模块设计的时候,占坑
就是先捋清思路流程,,然后再开始向里面写代码,,不至于直接报错
4.函数调用
新手经常犯的错误
- int add(2,3) 带了返回值类型
- add(int a, int b) 形参带类型了
一些见怪不怪的操作
函数可以当做表达式
函数调用当做其他函数调用的参数
4.形式参数和实际参数
传递参数,传递的是值,,形参和实参值相同,但是地址空间不同
#include <stdio.h>
//数据和值
int test(int x) //形式参数,需要包含变量类型,变量名(),,,,
/*生命周期:栈空间
*被调用的时候才为形式参数申请内存,调用结束,内存有被系统释放
*局部变量的有效作用空间(作用域)要记得*/
{
int y=5;
printf("test的x内存地址是%p,数值是%d\n",&x,x);
return (x-y);
}
//变量的四个要素:名 类型 值 地址
int main()
{
int x,y;
puts("请输入一个数:");
scanf("%d",&x);
printf("main的内存地址是%p,数值是%d\n",&x,x);
y = test(x);//实际参数,,会把这个函数的返回值给到y
printf("x=%d,y=%d",x,y);
return 0;
}
/****我在单片机看见有一种操作
void delay(unsigned int j)
{
while(j--);
}
void main()
{
delay(1000); 他们用的是此方法来进行延迟,延迟函数的数值可改,所以延迟时间也可以改,是不是很具有参考意义??
}
*/
1.全局变量与局部变量
如果放到这些函数的外面,,就是全局变量,对所有函数都生效,。
编程案例
1.输入两个整数,要求输出最大值,用函数实现
#include <stdio.h>
int get_bigger_fordata(int x,int y)
{
/*方法1
* int z;
* if(x>y){
* z = x;
* }else{
* z = y;
* }
* return z;*/
/*方法2
* int z;
* z =x>y?x:y
* return z;*/
/*方法3
return x>y?x:y;*/
}
int main()
{
int x,y,bigone;
//提示输入两个数
puts("输入两个数\n");
//输入两个数
scanf("%d%d",&x,&y);
//调用函数比较大小
bigone = get_bigger_fordata(x,y);
//输出输入的两个数,比较出那个数最大
printf("你输入的两个数分别是%d,%d, 最大的那一个是%d\n",x,y,bigone);
return 0;
}
这里我犯了一个大毛病就是在用 scanf 函数时需要取地址&,没有用的话,编译会出现这种情况
其次注意puts后面的\n,直接跳过了一格,puts是自动换行的
如果是小数或者字符呢??自行体会
调用过程
内存空间
值传递
值返回
(如果函数返回类型是void,函数体可以不用加return,返回值要注意类型,如果类型不同,可能会发生强制转换影响结果或编译警告)
内存释放(如果想要发生值改变,后面可以学到指针之后可以用指针传递地址)
函数调用的条件
函数已被定义
调用库函数
函数的声明
5.函数的嵌套
一步步调用,一步步返回
练习
用函数嵌套来实现四个数里取得最大值
#include <stdio.h>
int getfortwo(int a,int b)
{
return a>b?a:b;
}
int get_four_fordata(int a,int b,int c,int d)
{
int max;
max = getfortwo(a,b);
max = getfortwo(max,c);
max = getfortwo(max,d);
return max;
}
int main()
{
int a,b,c,d,best;
puts("请输入四个数");
scanf("%d%d%d%d",&a,&b,&c,&d);
getchar();
best = get_four_fordata(a,b,c,d);
printf("你输入的四个数分别是%d,%d,%d,%d,最大的是%d\n",a,b,c,d,best);
return 0;
}
6.函数的递归(嵌套了自己)
一般在实际中很少用
编程案例
解题思路
#include <stdio.h>
int get(int a)
{
int age;
//那么通过if语句,如果你想得到的不是1,那么他会一直在调自己,直到=1之后,输出age的值
//假如a=2;age = get(1)+2;,,然后这个get(1)就会调自己,get(1)=10,这样就可以得出结果了
if(a == 1)
{
age = 10;
}else{
age = get(a-1)+2;//这里我就有一个问题,什么时候才可以让它停下??
}
return age;
}
int main()
{
int age,num;
printf("请输入你想知道第几个学生的年龄\n");
scanf("%d",&num);
age = get(num);
printf("第%d的年龄为%d",num,age);
return 0;
}
一开始写成了if(a=1),他就变成了一个定值,就会出现下面的这种情况
求阶乘
//我直接改上面的代码哈哈哈哈,,需要注意的就是数过大就会越界
#include <stdio.h>
int get(int num)
{
int b;
//那么通过if语句,如果你想得到的不是1,那么他会一直在调自己,直到=1之后,输出age的值
//假如a=2;age = get(1)+2;,,然后这个get(1)就会调自己,get(1)=10,这样就可以得出结果了
if(num == 1)
{
b = 1;
}else{
b = get(num-1)*num;//这里我就有一个问题,什么时候才可以让它停下??
}
return b;
}
int main()
{
int b,num;
printf("请输入你想知道几的阶乘\n");
scanf("%d",&num);
b = get(num);
printf("%d的阶乘为%d",num,b);
return 0;
}
7.数组作为函数中的参数
传递数组中的某个元素(意义不大)
//我要传递过来单个数组怎么弄?
#include <stdio.h>
void printfdata(int data)//注意这里是一个普通的整型数,,而不是数组
{
printf("%d\n",data);
}
int main()
{
int array[] = {5,6,4,2,9,7};//这个拓展一下,就是为了看看,不定义数组大小会不会报错,结果是不会
for(int a = 0;a<6;a++)
{
if(a == 5)
{
printf("\n");
}
printf("%d ",array[a]);
}
int arr[3] = {1,2,3};
printfdata(arr[2]);//我们把第三个数给传过去
return 0;
}
数组名当做函数实际参数
//我要是传递整个数组呢?
#include <stdio.h>
void printf_arr(int arr[3])//把这三个数组定义出来
{
for(int a=0;a<3;a++){
printf("%d\n",arr[a]);
}
}
int main()
{
int arr[3] = {1,2,3};
printf_arr(arr);//这样会直接把整个数组给传递过去
return 0;
}
关于数组作为函数参数的一些坑
//还是用的上面的代码,我们算一下数组的分别在实参和形参的大小
#include <stdio.h>
void printf_arr(int arr[3])//把这三个数组定义出来
{
for(int a=0;a<3;a++){
printf("%d\n",arr[a]);
}
printf("arr里面的array%d\n",sizeof(arr));//注意计算大小时是arr数组名,而不是数组元素
}
int main()
{
int arr[3] = {1,2,3};
printf_arr(arr);//这样会直接把整个数组给传递过去
printf("main里面的array%d\n",sizeof(arr));//注意sizeof是关键字而不是函数
return 0;
}
//如果数组的个数变成10个呢?
#include <stdio.h>
void printf_arr(int arr[10])//把这三个数组定义出来
{
for(int a=0;a<10;a++){
printf("%d\n",arr[a]);
}
printf("arr里面的array%d\n",sizeof(arr));//注意计算大小时是arr数组名,而不是数组元素
}
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
printf_arr(arr);//这样会直接把整个数组给传递过去
printf("main里面的array%d\n",sizeof(arr));//注意sizeof是关键字而不是函数
return 0;
}
我们看到,实参变成了40个字节,一个int整型数大小为4个字节,,但是形参依旧是固定的8个字节
//下面我们开始分析一下
//至于上面会出现一个警告我们不需要管,还没有学到指针
#include <stdio.h>
void printf_arr(int arr[10],int len)//形参中不存在数组的概念,即便中括号约定了数组的大小,也是无效的
//void printf_arr(int arr[],int len),,,不写数组元素的个数也是对的
{ //传递过来的是一个地址,数组的首地址
for(int a=0;a<len;a++){
printf("%d\n",arr[a]);
}
printf("arr里面的array%d\n",sizeof(arr));//在OS操作系统中,用8个字节来表示地址
}
int main()
{
//里面还存在一个问题是,我们改变数组长度之后,函数封装里面的数组长度也需要更改,正常的我们一般不喜欢去更改函数里面的逻辑
//那么我们能不能直接计算出数组的长度呢?
int len; //优化部分
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
len = sizeof(arr)/sizeof(arr[0]);//一个好方法
printf_arr(arr,len);//这里需要注意把len的值也给传递过去
//1.数组名代表整个数组的首地址
//2.那么既然上面说到数组传递的是一个首地址,那么我们也可以这样写, printf_arr(&arr[0]);把数组第一个元素的地址传过去
printf("main里面的array%d\n",sizeof(arr));
return 0;
}
有意思的案例,关于地址(未来的指针)
当发生函数调用的时候,会开辟出一个地址给这个函数,此时这个数的改变只会在新开辟的地址里面改变,原先main函数里面的数值是不会变的
而当他传递数组时,却能改变数值,是因为他传递过去的是一个数组的首地址。。。
编程案例
算出两个班级学生成绩的平均分(API)
#include <stdio.h>
void initarray(int array[],int len)
{
for(int a=0;a<len;a++)
{
printf("请输入第%d个学生的分数\n",a+1);
scanf("%d",&array[a]);
}
}
void printfarray(int array[],int len)
{
printf("总共有%d个学生\n",len);
for(int a=0;a<len;a++)
{
printf("他们的成绩依次为%d\n",array[a]);
}
}
float average(int array[],int len)
{
int sum = 0;
float aver = 0.0;
for(int a=0;a<len;a++)
{
sum+=array[a];
}
aver = (float)sum/len;
return aver;
}
int main()
{
int classone[5];
int classtwo[10];
float averclassone;
float averclasstwo;
int lenclassone = sizeof(classone)/sizeof(classone[0]);
int lenclassatwo = sizeof(classtwo)/sizeof(classtwo[0]);
/*这是我一开始写的函数,垃圾的要死哈哈哈,下面来优化一下
initclassone();
initclasstwo();
printfclassone();
printfclasstwo();
averclassone();
averclasstwo();*/
//首先我们来解释一下什么叫API,它预先把复杂的操作写在一个函数里面,编译成一个组件(一般是动态链接库)程序员只需要简单的调用
//这些函数就可以用完成复杂的工作。
//这些封装好的函数就叫做API。更加通俗讲:别人写好的代码,或者编译好的程序,提供给你使用,就叫作api。
initarray(classone,lenclassone);
initarray(classtwo,lenclassatwo);
printfarray(classone,lenclassone);
printfarray(classtwo,lenclassatwo);
averclassone = average(classone,lenclassone);
averclasstwo = average(classtwo,lenclassatwo);
printf("第一个班的平均分为%f\n",averclassone);//一开始这里用%d来承接了,结果直接算不出来结果
printf("第二个班的平均分为%f\n",averclasstwo);
return 0;
}
8.二维数组作为函数的参数,他的形参怎么写?
正确写法
int arr[ 5 ] [ 2 ], int arr [ ] [ 5];
错误写法
int [ ] [ ]
/*回顾一下之前的二维数组*/
#include <stdio.h>
int main()
{
int i,j;
int arr[2][3] = {{4,5,6},{7,8,9}};
for(i=0;i<2;i++)
{
for(j=0;j<3;j++)
{
printf("%d",arr[i][j]);
}
putchar("\n");
}
return 0;
}
/*封装成函数的形式*/
#include <stdio.h>
void printf_arr_double(int arr[][])//3.所以这里就出错了
{
int i,j;
for(i=0;i<2;i++)
{
for(j=0;j<3;j++)
{
printf("%d",arr[i][j]);
}
putchar("\n");
}
}
int main()
{
//1.我们要关心的是每一维数组里面包含的元素数
int arr[2][3] = {{4,5,6},{7,8,9}};//2.特殊的一维数组,每个元素又是一个数组,大小确定
printf_arr_double(arr);
return 0;
}
然后你就会发现会爆错误
关心两点
- 数组数据类型
- 二维中的一维数组有多少个
练习
练习:有3x4矩阵,初始化它并输出,然后求最大值并输出
#include <stdio.h>
void init_arry(int arr[][4],int hang,int lie)
{
int i,j;
for(i=0;i<hang;i++)
{
for(j=0;j<lie;j++)
{
printf("请输入第%d行,第%d列的数\n",i+1,j+1);
scanf("%d",&arr[i][j]);
}
}
}
void printf_arr_double(int arr[][4],int hang,int lie)
{
int i,j;
for(i=0;i<hang;i++)
{
for(j=0;j<lie;j++)
{
printf("%d ",arr[i][j]);
}
putchar('\n');//注意这个要用单引号啊啊啊啊啊啊!!!
}
}
int get_max_arr_double(int arr[][4],int hang,int lie)
{
int i,j;
int max =arr[0][0];
for(i=0;i<hang;i++)
{
for(j=0;j<lie;j++)
{
if(max < arr[i][j])
{
max = arr[i][j];
printf("最大的数在第%d行,第%d列",i+1,j+1);
}
}
}
return max;
}
int main()
{
/*1.把数组几行几列给输入进去
*2.把数组遍历打印出来
*3.获取出最大值*/
int x,a;
int arr[3][4];
init_arry(arr,3,4);
printf_arr_double(arr,3,4);
a = get_max_arr_double(arr,3,4);
printf("最大的数为%d",a);
return 0;
}
9.全局变量
编程案例
班上10 个学生,封装一个函数,调用该函数后获得班上的平均分,最高分,最低分
#include <stdio.h>
//我们没有办法返回多个值,所以只能定义一个全局变量来承接这个数
int min,max;
float aver;
float quanjv(int score[],int len)
{
int sum = 0;
min = max = score[0];
for(int i = 0;i<len;i++){
if(min>score[i]){
min = score[i];
}
if(max <score[i]){
max = score[i];
}
sum +=score[i];
}
return (float)sum/len;
}
int main()
{
//1.做出一个数组
//2.调用函数,返回平均值
int score[10] = {12,54,15,2,65,88,41,34,51,62};
float len = sizeof(score)/sizeof(score[0]);
aver = quanjv(score,len);
printf("最大的数是%d,最小的数是%d,平均分是%f",max,min,aver);
return 0;//返回值只能返回一项,以后学了结构体之后可以返回多个值
}
练习题
1.要求输入10个数,找出最大数以及最大数的下标
#include <stdio.h>
int j;
void init_total(int arr[],int len)
{
printf("请依次输入10个数\n");
for(int a = 0;a<len;a++)
{
scanf("%d",&arr[a]);
}
}
int find_max(int arr[],int len)
{
int max = arr[0];
for(int i = 0;i<len;i++)
{
if(max < arr[i])
{
max = arr[i];
if(max == arr[i])
{
j = i;
}
}
}
return max;
}
int main()
{
int arr[10];
int maxx;
int len = sizeof(arr)/sizeof(arr[0]);
//1.提示输入
init_total(arr,len);
//2.存放起来
//3.找最大数以及下标
maxx = find_max(arr,len);
printf("最大值为%d,他是第%d个元素\n",maxx,1+j);
return 0;
}