友友们,如果你认真读完这篇文章,恭喜你,在函数的基本使用这方面,已经没什么大问题了。(真的吗真的吗那太好了哈哈哈)中国人不骗中国人,我们开始吧。
目录
为什么要使用函数?
对程序员来说,"代码复制"使程序质量不良的表现。在编程的过程中,有些程序会多次使用,为了使程序变得更加简洁与模块化,我们把这些经常使用的代码封装起来,形成函数。
1.概念
提起函数,我们会想到初高中数学里的y=f(x),即给定一个x,通过f()的作用,得到一个y值。其实C语言中的函数也是这样。给函数输入一个参数,通过函数特定的作用,实现某种结果。所不同的是,C语言中的函数并不都有返回值(void)。
简单来说,函数是一块代码,接收零个或多个参数,做一件指定的事情,返回零个或一个值。
注意哦,输入可以有多个,但返回值最多只能有一个。
《C primer Plus》中写到:什么是函数?函数是完成特定任务的独立程序单元。
函数主要分为两种:库函数和自定义函数。让我们来看看吧!
2.库函数
在开发的过程中,有很多功能会被频繁大量的使用,为了支持程序可移植性和提高程序的效率,我们把这些功能统一封装到库函数里,方便程序员进行软件开发。
C语言常用的库函数:
- IO函数(输入输出函数)(printf scanf getchar putchar)
- 字符串操作函数(strcmp(比较字符串) strlen(求字符串长度))
- 字符操作函数(大小写转换等)
- 内存操作函数(mecpy memcmp memset)
- 时间/日期函数(time)
- 数学函数(sqrt pow)
- 其他库函数
查询工具:
库函数需要全部记住吗?不需要,但是我们要学会使用查询工具。在这里,给大家提供三个网站,帮助大家查询。
- www.cplusplus.com(推荐使用!可以查C也可以查C++)
打开后的界面就是这样了,在搜索栏里输入想要查询的库函数,点击搜素,就会看到此函数的详细信息。
- MSDN官网(Microsoft Developer Network)支持在线浏览
- zh.cpprefence.com(c/c++官网,但是加载速度比较慢)
3.自定义函数
自定义函数和库函数一样,有函数名,返回值类型和参数(表)。但是不一样的是这些都需要我们自己来设计,这就为程序员提供了一个很大的发挥空间。
函数的组成形式:
以下面这段代码为例,来看看函数的组成形式:
在这里,我们发现,函数名后面跟了一个圆括号。从某种意义上来讲,圆括号表明这是一个函数,而不是一个变量。()起到了函数调用的重要作用,所以即使没有参数也需要()。不信我们来看看下面这段代码:
可以看到,我们确实定义了“cheer”这个函数,但由于在主函数中“调用”的时候,忘记了带圆括号,导致没打印出我们想要的。当我们加上圆括号时,才表示该函数真正的被调用:
一直在说函数的调用,这到底是什么呀?别急,等我们了解了实参和形参,才能更好地学习函数调用。
4.函数参数
函数参数有两种:实参和形参
实参:
调用函数的时候,实际传递过去的值叫实参。实参可以是:常量、变量、表达式、函数等。无论实参是何种类型的量,在进行函数调用时,它们都必须要有确定的值,以便把这些值传送给形参。
形参:
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。
我们可以认为,形参实例化后其实相当于实参的一份临时拷贝。
好啦,现在再来看函数的调用。
4.函数调用
我们知道,C程序是从main函数开始执行的。当在main函数中碰到其他函数时,就会启动相关函数的代码部分,完成相关命令。如果函数有参数,调用函数时必须传递给它数量、类型正确的值。可以传递给函数的值是表达式的结果,这包括:字面量、变量、函数的返回值、计算的结果。c语言在调用函数时,永远只能将值传给函数。
传值调用和传址调用
函数调用又分为两部分:
传值调用:函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参
- 每个函数都有自己的变量空间,参数也位于这个独立的空间中,和其他的函数没有关系。
- 对于函数参数表中的参数,叫做“形式参数”,调用函数时给的值,叫做“实际参数”
传址调用:传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量。
我们举个实例来说明一下。
求较大值
从第一行我们了解到,定义了一个函数get_max,该函数的返回值是整型,传入的值也是两个整型类型的。(其实一般在程序的开始,会有函数的声明来让我们知道将会用到哪些函数,但是由于这段代码中只定义了一个函数,所以我们省略了,友友们以后如果在一个项目中定义了比较多的函数,一定要在记得写函数声明奥)。然后直接从主函数开始看,先定义两个整型变量a和b,然后调用了get_max函数,将a、b的值传入该函数,让该函数帮我们完成求最大值的操作,并将结果以int类型传给max,我们只需要输出max。
int get_max(int x, int y)
{
int z = 0;
if (x > y)
z = x;
else
z = y;
return z;//返回Z,返回最大值
}
int main()
{
int a = 10;
int b = 20;
//函数的调用
int max=get_max(a, b);
printf("max=%d\n", max);
return 0;
}
到这里,大家对函数的调用应该已经有了一个大概的感知,我们再来以一个实例强化感知。
交换两个整型变量:
void swap1(int x, int y)//x,y是形参
//函数返回类型的地方为void,表示该函数不返回任何值,也不需要返回
{
int z = 0;
z = x;
x = y;
y = x;
}
int main()
{
int a = 10;
int b = 20;
printf("交换前A=%d,B=%d", a, b);
swap(a, b);
printf("交换前A=%d,B=%d", a, b);
return 0;
}
发现并没有交换?
这是因为在swap函数中,其实是给10、20开辟了一块新的内存(x和y),所以不管swap函数内部怎么调换,都不会影响原来a、b的值。
怎么改呢?这就需要用到指针了。我们把存放10、20的地址作为参数传给函数,问题就迎刃而解。这也就是我们前面提到的传址调用。
void swap2(int* pa, int* pb)
//函数返回类型的地方为void,表示该函数不返回任何值,也不需要返回
{
int z = 0;
z = *pa;
*pa = *pb;
*pb = z;
}
int main()
{
int a = 10;
int b = 20;
printf("交换前A=%d,B=%d", a, b);
swap(&a, &b);
printf("交换前A=%d,B=%d", a, b);
return 0;
}
本地变量
接下来我们学习一个新名词——本地变量。
本地变量
- 函数的每次运行,都会产生一个独立的变量空间,在这个空间中的变量,是函数的这次运行所独有的,称作本地变量。
- 定义在函数内部的变量就是本地变量
- 参数也是本地变量
变量都是有生命周期的。全局变量的生命周期是整个程序,那么本地变量呢?答案是大括号内,就是离这个变量最近的大括号内。只有在本地变量所处的大括号内——块,这个变量才会起作用。
本地变量是定义在块内的,它可以定义在函数的块内,也可以定义在语句的块内。程序进入这个块前,其中的变量不存在,离开这个块,其中的变量就消失了。
5.函数的嵌套调用和递归
嵌套调用
函数的嵌套调用就是在一个函数的内部调用另一个函数。在C语言程序设计中,允许多层嵌套调用。
递归
我们可以这样理解函数的递归调用:在一个函数内部,调用了这个函数本身(类似套娃),函数递归调用需要递归方式——给出调用方式、递归终止条件——避免程序陷入死循环。
比如,我们计算整数n的阶乘,就需要用到递归。
6.几个练习
最后,做几个练习题巩固一下吧!
输出100-200之间的素数
#include<stdio.h>
int is_prime(int n)
{
//用2—n-1之间的数字来试除
int j = 0;
for (j = 2; j < n; j++)
{
if (n % j == 0)
return 0;
}
return 1;
}
int main()
{
int i = 0;
int count = 0;
for (i = 100; i <= 200; i++)//生成100-200之间的数
{
if (is_prime(i) == 1)//判断是否为素数
{
printf("%d ", i);//输出素数
count++;
}
}
printf("\n共有%d个素数\n", count);
}
写一个函数输出1000-2000的闰年
闰年判断条件:可以被4整除不可以被100整除 或 可以被400整除
//如果是闰年,返回1
//如果不是,返回0
#include<stdio.h>
int is_leap_year(int n)
{
if (((n % 4 == 0) && (n % 100 != 0)) || (n % 400 == 0))
return 1;
else
return 0;
}
int main()
{
int y = 0;//y代表年份
int count = 0;
for (y = 1000; y <=2000; y++)
{
if (is_leap_year(y) == 1)
{
printf("%d\n", y);
count++;
}
}
printf("1000-2000共有%d个闰年\n",count);
return 0;
}
求两个数的最小公倍数
//求两个整数的最大公约数(辗转相除法)
int fun1(int m, int n)
{
int r;
while ((r = m % n )!= 0)
{
m = n;
n = r;
}
return n;
}
//求两个函数的最小公倍数
//最小公倍数:两数相乘除以他们的最大公约数
int fun2(int n1, int n2)
{
int gbs1;
gbs1 = n1 * n2 / fun1(n1, n2);//调用fun1()
return gbs1;
}
void main()
{
int num1, num2,gys, gbs;
printf("输入两个数字:\n");
scanf_s("%d %d", &num1, &num2);
gys = fun1(num1, num2);
gbs = fun2(num1, num2);
printf("最大公约数为%d\n", gys);
printf("最小公倍数为%d\n", gbs);
}
今天的分享就到这里啦。