1.函数是什么
在数学里,函数是一种对应关系,而 C
语言里的函数和数学中的函数具有相似点,但是有很大的不同,甚至有些人认为“函数”这个名词不够恰当。准确来说,C
函数的函数是一种子程序,您可以去 Wiki 百科查看对子程序的解释。
所谓的子程序,实际上就是大型程序中的某部分子代码。子程序本身由一个或多个语句组成,负责完成某项特定的任务,而且相较于其他代码具有相对的独立性。
可以认为,程序员在实践中,发现某一段代码也就是子程序经常被反复使用,因此就将这段代码摘取出来,给其进行命名做标记。而后续编码过程中,如果需要使用这段代码,就只需要调用对应的命名标记即可。
//计算算式 (x + y) / 3 - z 的结果
#include <stdio.h>
int main()
{int val1 = (1 + 2) / 3 - 4;printf("%d\n", val1);int val2 = (6 + 3) / 3 - 5;printf("%d\n", val2);int val3 = (-3 + 4) / 3 - 7;printf("%d\n", val3);return 0;
}
可以看到,我们反复使用下面这段子代码:
//提炼出子代码
#include <stdio.h>
int valn = (x + y) / 3 - z;
printf("%d\n", valn);
如果需要计算的次数变多,就会重复写上述的子代码,这样做的效率实在太低,因此我们把子代码摘取出来,给予一个标记/函数名作为子代码的命名,这个过程也被称为“封装”。
//把子代码封装为函数
#include <stdio.h>
void Function(int x, int y, int z)
{int valn = (x + y) / 3 - z;printf("%d\n", valn);
}
那怎么调用呢?看下面代码:
//把子代码封装为函数
#include <stdio.h>
void Function(int x, int y, int z) //接受三个参数拿去计算并且输出结果
{int valn = (x + y) / 3 - z;printf("%d\n", valn);
}//计算算式 (x + y) / 3 - z 的结果
int main()
{//int val1 = (1 + 2) / 3 - 4;//printf("%d\n", val1);Function(1, 2, 4); //传递三个参数交给函数去计算//int val2 = (6 + 3) / 3 - 5;//printf("%d\n", val2);Function(6, 3, 5); //传递三个参数交给函数去计算//int val3 = (-3 + 4) / 3 - 7;//printf("%d\n", val3);Function(-3, 4, 7); //传递三个参数交给函数去计算return 0;
}
这样就简化了 main()
函数内冗余的代码。
吐槽:不过函数这个名字实际上我感觉也没错,上述例子中的确是进行了输入和输出,看上去也挺像数学里的函数或方程…
这里强调一点,使用函数时也是需要使用空间的,这类似创建变量需要有空间存储变量的值一样,函数在运行过程中也需要一定的空间资源,而这份空间也被叫做栈区,您简单理解一下就行。
2.函数的传参
实际参数 就是真实传给函数的参数,实参可以是常量、变量、表达式、函数返回值…在进行函数调用的时候,必须先有实际参数调用函数,然后再传值/拷贝给函数的 形式参数,在函数体内部进行使用。
补充:“传值”这个词,在计算机中很多时候都是“拷贝”的代名词…
而简单来讲:
- 函数调用后,函数名后面括号的内容中的量就是实际参数
- 函数定义后,函数名后面括号的内容中的变量就是形式参数
//区分实参和形参
#include <stdio.h>
void Func(int x) //这里的 x 就是形式参数
{printf("%d\n", x);
}int main()
{int t = 0;Func(t); //这里的 t 就是实际参数Func(2); //这里的 2 就是实际参数return 0;
}
只有在函数被调用的时候,实参传值给形时,形参才会有值(即“才会实例化“)此时该变量才会分配内存单元,拷贝一份实参的值来使用。
而由于“形参”是“实参”的一份临时拷贝,因此对形参的任何修改是不会影响到实参的。这样就会造成一些坑。
//使用传值的交换函数
#include <stdio.h>
void Swap(int x, int y) //用于交换两个数的函数
{printf("x=%d y=%d\n", x, y); //打印检查是否有发生交换int temp = x; //先存储一份 x, 避免 x 原本的值丢失x = y;y = temp;printf("x=%d y=%d\n", x, y); //打印检查是否有发生交换
}int main()
{int a = 1;int b = 2;printf("a=%d b=%d\n", a, b); //打印检查是否有发生交换Swap(a, b); //尝试交换两个变量中的值printf("a=%d b=%d\n", a, b); //打印检查是否有发生交换return 0;
}
我们会发现,a
和 b
变量内的值确实没有发生交换,但是函数体内的形参却做了交换,但是这个交换结果没有影响到身为实参的 a
和 b
变量。因此,如果我们需要通过形参来改动实参,则不能只是传递值,而是应该传递实参的地址!