前面我已经写过一篇有关C语言初阶函数的博客,讲解了C语言中函数的基础知识。这篇博客我会总结一下前面已经讲解过的内容,并作适当拓展。
函数就是子程序,也就是一段代码用于完成一项特定的功能。函数分为库函数和自定义函数。库函数可以理解为C语言自带的函数(其实准确的说是C语言语法规定了一些函数的功能,然后由编译器实现)。使用库函数必须包含对应的头文件。
自定义函数是由程序员自己来写的函数,包含函数名,返回值类型,函数参数。
举个例子。写一个函数返回两个整数的较大值。
首先写出主函数:
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
int ret = get_max(a, b);
printf("%d\n", ret);
return 0;
}
这里我们输入两个值存入a,b两个变量中,然后用get_max函数找到较大值,返回这个较大值后用ret接收,然后输出在屏幕上。接着写这个get_max函数。
int get_max(int x, int y)
{
return x > y ? x : y;
}
关于x>y?x:y的讲解,我在前面讲解操作符的博客中有提到,作用是求出x和y的较大值。在这个函数中,get_max是函数名,函数名后面跟的括号里面写的是函数传的参数,这里我们要传递的是两个整数,函数名前面的int是返回值类型,由于返回的是两个整数的较大值,也是整数,所以写的int。
这里a和b叫做实参,x和y叫做形参,简单来说,定义函数时括号里的叫做形参(x和y),调用函数时括号里的叫做实参(a和b)。
这个函数比较简单,我相信看过我对函数初阶讲解的朋友都能很容易写出来。接下来讲个复杂点的,用函数交换两个整型变量。这个问题看似简单,但很多朋友第一遍都写不对。请你仔细看看我下面的写法有什么问题。
先写出主函数:
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
printf("交换前:a=%d b=%d\n", a, b);
Swap(a, b);
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}
接着写出Swap函数:
void Swap(int x, int y)
{
int tmp = x;
x = y;
y = tmp;
}
看出问题了吗?如果没有看出来,我们先运行一下:
有没有发现,a和b压根就没有交换?
我们想要这个函数实现交换变量的功能,但是它却没按照我们的意思进行。这说明中间有猫腻!这时我们就要通过调试来找到错误。由于篇幅有限,我会在后面专门出一期博客讲解如何调试,这里就直接分析代码。
我们在主函数中创建了a和b两个变量,并且输入了3和5,此时a是3,b是5,此时我们调用Swap函数,把a中的3传给了x,把b中的5传给了y,此时x是3,y是5。注意了!a和b,x和y是完全不同的几块空间!我们这时在函数中交换了x和y的值,对a和b完全没有任何影响!所以这么写是错误的。
在调用这个Swap函数时,我们把a和b的值传递给了函数,这种函数调用方法被称为传值调用。传值调用时,函数形参是实参的一份临时拷贝,改变形参不影响实参!
那正确的写法是什么呢?
这时指针就要派上用场了。只要把所有传值部分改成地址就行了。写法如下:
void Swap(int* px, int* py)
{
int tmp = *px;
*px = *py;
*py = tmp;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
printf("交换前:a=%d b=%d\n", a, b);
Swap(&a, &b);
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}
运行结果:
为什么传递指针就可以了呢?
因为我们把a和b的地址传给了Swap函数,px就指向了a,py就指向了b,我们就能在Swap函数内部找到a和b所在的内存空间,也就能操作a和b的值了!
这种传递地址的调用方式叫做传址调用。传址调用时,函数可以建立形参和实参之间的联系,可以真正的通过形参找到实参,从而改变实参的值。
也就是说,当我们不需要改变实参的值时采取传值调用,如果需要改变实参的值则采取传址调用。
关于函数还有一些比较简单的知识,这里稍稍总结一下。
在一个函数内部调用另一个函数,叫做函数的嵌套调用。这里需要注意,函数可以嵌套调用,但不能嵌套定义!
把一个函数的返回值作为另一个函数的参数,叫做函数的链式访问。
函数的声明是告诉编译器函数名,参数类型和返回值类型。比如上面Swap函数的声明如下:
void Swap(int* x, int* y);
函数声明时,形参名可以省略。所以也可以这么写:
void Swap(int*, int*);
函数的定义就是正常的实现函数的具体功能。
函数一定要先声明再使用!函数的声明一般包含在头文件中。
最后还有一块很重要的知识,就是函数的递归。我会放在之后的博客中讲解。
感谢你的阅读,喜欢的话就点个赞吧!