函数
基本语法
返回类型 函数名(形参列表)
{
执行语句;
返回值}
#include <stdio.h>
double cal(int n1,int n2,char oper){
double res = 0.0f;//定义一个变量接收返回值
switch(oper){
case '+':
res = n1 + n2;
break;
case '-':
res = n1 - n2;
break;
case '*':
res = n1 * n2;
break;
case '/':
res = n1 / n2;
break;
default:
printf("请输入四则运算符");
}
printf("%d %c %d = %f\n",n1, oper, n2, res);
}
int main(void) {
cal(3,2,'/');
printf("%f",3.0f/2.0f);
return 0;
}
头文件
头文件里包含了声明和宏定义,被多个源文件引用共享,不同的文件里定义了不同的函数,在头文件中声明函数,在源文件中定义函数
可以把所有的常量,宏,系统全局变量,函数原型写在头文件中
- 标准库提供
- 自己写
使用头文件中声明的函数
#include<>引用系统头文件,是在系统的目录下方寻找,效率更高
#include“ ”:可以引用系统头文件和自己的头文件,会在编译器指定的目录下寻找。
多次引用头文件不会报错,因为有代码防重复机制。
头文件只能包含函数的声明,不能包含定义
调用机制
程序执行到主函数时,计算机会在栈中开辟一个独立的空间:main栈,在栈中有了独立的变量,当执行main函数中自定义的函数时,栈中会开辟另一个独立的空间,函数栈(开辟了新栈)。在新的栈中执行相应语句,执行完(或者遇到return语句)后重新返回到main栈中函数所在的位置,继续执行,为函数开辟的栈被销毁。如果函数有返回值,就把此值返回给接收的变量。
转换数据类型的方法(int)n
每个栈空间是独立不冲突的
递归调用
递归调用时,当最后一个调用停止时,函数会返回一个值,此栈被销毁,转到上一个调用的地方,此时返回的值是上一个调用的n值,因为下一个栈已经被销毁
函数的栈都是相互独立的,不影响
递归条件必须向退出递归的条件逼近,都则会发生栈溢出
斐波那契数列
#include <stdio.h>
int fnb(int n){
if(n==1||n==2){
return 1;
}
else{
return fnb(n-1) + fnb(n-2);
}
}
int main(void) {
int num = 2;
num = fnb(num);
printf("n = %d\n", num);
return 0;
}
猴子吃桃:有一堆桃子,猴子第一天吃了其中的一半,又吃了一个,以后猴子每天这样吃,在第10天去吃时发现还剩一个桃子,问原来有多少桃子
#include <stdio.h>
int fn(int n){
if(n==10){
return 1;
}
else{
return 2*(fn(n+1) + 1);
}
}
int main(void) {
int num = 1;
num = fn(num);
printf("n = %d\n", num);
return 0;
}
参数传递
如果想要函数内的变量影响到函数外的变量,使用指针传递
f(&n):&n取的是n变量的地址,函数参数进行接收时int *p
p
中是地址,*p
取的是p指针指向的变量,即使栈销毁了,但改变的是main栈中的值。
不支持函数重载不能通过参数的个数不同或类型不同来区分函数。
支持可变参数
#include <stdio.h>
#include <stdarg.h>
int fun(int num, ...)//可变函数,即参数的个数可以不确定,使用三个点表示
{
int i, totalSum = 0;
int val = 0;
va_list v1; //V1实际上是一个字符指针,从头文件中可以找到
va_start(v1, num); //使用v1指向可变列表中的第一个值,即num后的第一个参数
printf("*v = %d\n", *v1);
for (i = 0; i < num; i++)//按照num遍历
{
val = va_arg(v1, int);//该函数返回v1的值,并使v1向下移动一个int的距离,使其指向下一个int
printf("res = %d\n", val);
totalSum += val;
}
va_end(v1);//关闭v1指针,使其指向null
return totalSum;
}
void main() {
fun(3, 30, 20, 11);//在3后面需要输入3个数
printf("%d", res);
}
传递指针(引用传递)
#include <stdio.h>
//编写一个函数,可以交换n1,n2: swap(int *n1, int *n2)
void swap1(int* n1, int* n2) {//在为swap函数开辟的栈中,n1,n2在swap中有自己的地址,只是n1,n2保存的是在main栈中n1,n2的具体地址
int temp = *n1;//把n1指针指向的变量值赋给temp变量,*代表解析,取在swap栈中n1保存的地址对应的值
*n1 = *n2;//n1指针在上一步操作后没有值,所以接下来把n2指针指向的变量值赋给n1这个指针指向的变量
*n2 = temp;//把ntemp变量指向的值值赋给n2这个指针指向的变量
}
void swap2(int n1, int n2) {//在为swap函数开辟的栈中,n1,n2在swap中有自己的地址,只是n1,n2保存的是在main栈中n1,n2的具体地址
int temp = n1;//把n1指针指向的变量值赋给temp变量,*代表解析,取在swap栈中n1保存的地址对应的值
n1 = n2;//n1指针在上一步操作后没有值,所以接下来把n2指针指向的变量值赋给n1这个指针指向的变量
n2 = temp;//把ntemp变量指向的值值赋给n2这个指针指向的变量
}
void main() {
int n1 = 1;
int n2 = 2;
swap2(n1, n2);//传递参数时传递的是n1,n2在栈中的地址
printf("n1 = %d, n2 = %d\n", n1, n2);
swap1(&n1, &n2);//传递参数时传递的是n1,n2在栈中的地址
printf("n1 = %d, n2 = %d", n1, n2);
}
不管是值传递还是引用传递,传递都是变量的副本,只不过值传递传递的是值的拷贝,而引用传递传递的是地址的拷贝,地址拷贝效率高,因为数据量小,值拷贝取决于拷贝数据的大小,数据越大,下效率越低。
引用传递的类型有:数组,指针