1.5函数类型的讲解

包含内容:自定义函数的使用,形参和实参,return语句的总结,数组传参的注意事项,函数嵌套链式访问,多文件处理方法,静态库封装函数定义,static与extern关键字的使用

自定义函数

ret_type
fun_name
(
形式参数
)

{

}

ret_type
是函数返回类型 

可能返回的是整形,那就用int接受,如果什么都不返回(输出结果有误)就返回void

fun_name
是函数名   最好是有具体意义对于要求的条件,比如要求两个数最大值就可以命名sum

括号中放的是形式参数  

{ }括起来的是函数体   函数体就是用来计算过程

eg 求两个数的和



int sum (intx,inty) //类型命名和形参
{
 
return x+y; //返回的是两个数的和
}
 
 
int main()
{
int a=2;
int b=3;
int r=sum(a+b); //调用上面写好的函数
printf("%d",r)
return 0;
}

形参与实参

刚刚上面的代码注释上面有提到形参,那什么是形参呢?

通俗的举例子就是没有实际意义的参数就叫做形参,而具有用处的参数叫做实惨

在上面的代码中间我们可以看到x与y其实并没有调用,只是为了给c语言展示我写的自定义函数的作用,知道下面的a与b才开始用于计算并调用空间内存

. return 语句

在函数的设计中,函数中经常会出现return语句,这⾥讲⼀下return语句使⽤的注意事项

return一般后面都会跟一个数值或者是表达式,如果是表达式则计算后返回结果;但当函数类型是void类型(无返回类型)的时候,也可以直接return;结束

return语句相比于break更加厉害,break只是结束循环,但是return是结束函数

函数的返回类型如果不写,编译器会默认函数的返回类型是int

但是当return定义的类型与后面不一样就会自动更正,比如一开始是int,后面返回的是double类型1.3,则最终返回的是整形1的结果

如果函数中存在if等分⽀的语句,则要保证每种情况下都有return返回,否则会出现编译错误

数组作为函数参数

我们设计一个题目把自定义函数和数组的内容结合在一起

写⼀个函数将⼀个整型数组的内容,全部置为1,再写⼀个函数打印数组的内容

我们的思路是写一个数组,设计一个函数把内容置为1,在设计一个函数打印出来



#include<stdio.h>
int main()
{
int arr[10]={1,2,3,4,5,6,7,8,9,10}
set_arr()
prin_arr()
return 0;
}

set_arr函数就是我们用来把内容置为1,而prin_arr()就是用来打印

这里函数的命名不唯一,只要命名有意义,你像prin就是printf打印的意思,就是至少是你想法的英文,而且setarr也行,setArr也行,但是不可以set  arr,中间不可以空格。

这里的set_arr函数要能够对数组内容进行设置,就得把数组作为参数传递给函数,同时函数内部在设 置数组每个元素的时候,也得遍历数组,需要知道数组的元素个数。所以我们需要给set_arr传递2个参 数,⼀个是数组,另外⼀个是数组的元素个数。仔细分析print_arr也是⼀样的,只有拿到了数组和元 素个数,才能遍历打印数组的每个元素

所以元素个数我们这么求



#include<stdio.h>
int main()
{
int arr[10]={1,2,3,4,5,6,7,8,9,10}
set_arr()
int num = sizeof(arr)/sizeof(arr[0])
prin_arr()
return 0;
}

sizeof(arr)是求出整个数组的字节大小,而sizeof(arr[0])则是数组一个元素的字节大小

我们开始写这两个自定义函数



void set_arr(int arr[], int num)
{
 int i = 0;
 
 for(i=0; i<num; i++)
  {
 arr[i] = 1;
  }
}
 
void prin_arr(int arr[], int num)
{
int i = 0;
 for(i=0; i<num; i++)
 {
 printf("%d ", arr[i]);
 }
printf("
");
}
 
 
#include<stdio.h>
int main()
{
int arr[10]={1,2,3,4,5,6,7,8,9,10};
set_arr(arr, num);
int num = sizeof(arr)/sizeof(arr[0]);
prin_arr(arr, num);
return 0;
}

这俩个函数我们只需要让计算机知道我们自定义函数是怎么使用就可以了,不需要返回什么数据

函数的形式参数要和函数的实参个数匹配:如果实参有两个,那么形参也要有两个

函数的实参是数组,形参也是可以写成数组形式的

比如实参我们用的是arr,num   

那么形参就要用int arr[ ],int num 要加上类型和arr[ ]

形参如果是⼀维数组,数组大小可以省略不写

形参如果是⼆维数组,行可以省略,但是列不能省略

这里我们借助豆包帮我生成例子

形参操作的数组和实参的数组是同⼀个数组 

函数嵌套

简单来说就是一个自定义函数可以在另一个自定义函数使用,但是记住自定义函数不可以在另一个自定义函数中定义,因为每一个函数的地位是一样的。

下面举个例子,写一个代码:输入年月可以判断天数



int whatyear (int y)   //定义函数判断是否为闰年
{
if(((y%4==0)&&(y%100!=0))||(y%400==0))//闰年的定义
return 1;
else
return 0;
}
 
int whatmonth (int y, int m) //自定义函数判断闰年则2月加1
{
    int days[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
//月份(数组下标)  0   1   2  3   4   5   6   7   8   9   10   11  12
 
int day = days[m];
 
if (whatyear(y) && m == 2)
//if(whatyear==1 && m==2)这样也可以,只不过当返回0的时候c语言自动认为成立
day += 1;
return day;
}
 
 
int main()
{
int y = 0;     //年份
int m = 0;     //月份
scanf("%d %d", &y, &m);
int d = whatmonth(y, m);
printf("%d
", d);
return 0;
}
 

这里whatmonth中就嵌套了whatyear的函数

链式访问

下面举个例子

这个就是链式,就是可以一直作为参数像个链子一样参与运算



#include <stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 43)));
return 0;
}

这里输出结果前我先告诉你一个网站(之前文章有提过)

https://legacy.cplusplus.com/reference/cstdio/fprintf/

打开看printf的用法,下面的是我用edge扩展的英语翻译过来的

所以可以看出printf返回的是数的个数

第三个printf打印43,在屏幕上打印2个字符,再返回2

第⼆个printf打印2,在屏幕上打印1个字符,再放回1

第⼀个printf打印1

所以屏幕上最终打印:4321

多文件处理方法

当我们开始具备写千行万行的实力,就不好在一个文件上敲这么多代码,而且想要多人一起写代码在一个文件一个电脑也不太现实,这个时候就可以采用多文件的方法

比如我们想要写一个加法的函数

我们可以在(源文件).c文件中定义和运算,在(头文件).h上声明

图片[1] - 1.5函数类型的讲解 - 宋马

这就是我们创建的三个文件

这样在后面运用加法函数直接调用即可,但是记得如果这样在调用的时候add时候要加上#add()

相当于头文件

那如果我们写一个代码被别人买了,但是又不想他知道我们代码的核心运算怎么办?

这个时候我们就可以在函数的定义上上把锁,让别人不看到我们的函数是怎么写的,这样哪怕他拿到代码也没有用。

右击鼠标点击引用上面自己命名的地方

在右击后最下面有一个属性,点击后

在点击静态库后,点击VS上面的生成解决方案

那我们就生成了一个.c.lib的静态库,这样就可以把生成的静态库.c.lib文件和我们声明的.h文件卖给商家,那她就只能使用我们学的代码但是不能看懂其中的逻辑。

但是作为买家的话我们并不能直接拿来就用,我们在打开这两个文件后要加上一个声明代表我们要使用这个静态库,pragma comment(lib,”文件2.c.lib”) 这个双引号里面就是你静态库的名称

static与extern关键字

static
是C语言中的关键字,是静态的的意思,可以用来:

 修饰局部变量 变成静态局部变量

 修饰全局变量 变成静态全局变量

 修饰函数        变成静态函数

在讲解
static
之前再讲⼀下:作用域和生命周期

作用域

 
局部变量的作用域是变量所在的局部范围,简单来说就是大括号里面

 
全局变量的作用域是整个工程(项目),简单来说就是全部代码都可以作用

生命周期

生命周期指的是变量的创建(申请内存)到变量的销毁(收回内存)之间的⼀个时间段

 局部变量的生命周期是:进⼊作⽤域变量创建,生命周期开始,出作用域生命周期结束

 
全局变量的生命周期是:整个程序的生命周期

现在展示static的用法之局部变量:可以使局部变量的生命周期像全局变量,但是作用域不变



void sec()
{
int n =0;
n++;
printf("%d",n);
}
 
int main()
{
for(i;i<=5;i++)
{
sec();
}
 
return 0;
 
}

这个函数输出的是11111,因为n是局部变量,出了大括号就会被销毁,这个时候n的值又是0,无限加1输出打印

那如果我们加上static结果就不一样了



void sec()
{
static int n =0;
n++;
printf("%d",n);
}
 
int main()
{
for(i;i<=5;i++)
{
sec();
}
 
return 0;
 
}

加上static以后n的生命周期发生了极大的改变,相当于全局变量(作用域没有变),这个时候n出大括号并不会被销毁,而是会被保留下来作为下一次进入的初始值。所以输出的是1,2,3,4,5

extern声明外部符号

用法和上面的#add.h差不多用法,但是#add.h是用来声明自定义函数的而extern是用来引入全局变量

但是如我们用static修饰全局变量,那么这个时候用extern的时候就没有用了(使用比较少,简略的讲)

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容