函数

  • 一、函数的调用机制
    • (一)、调用机制:程序员调用方法,方法给程序员返回结果
    • (二)、函数调用规则
    • 举例:判断函数调用是否正确。
  • 二、函数的递归调用
    • (一)、递归调用:一个函数在函数体内又调用了本身。
    • (二)、函数递归需要遵守的重要原则
    • 递归练习题
      • 1.斐波那契数
      • 2.求函数值
      • 3.猴子吃桃问题
  • 三、函数注意事项和细节讨论
    • 习题
      • 请编写一个函数swap(int *nl, int*n2)可以交换nl 和 n2的值。

一、函数的调用机制

(一)、调用机制:程序员调用方法,方法给程序员返回结果

举例:
(1)传入一个数+1 test函数

//第一题#includeint test(int n1){int sum = n1 + 1;printf("sum = %d",sum);return 0;}void main(){int n2=6;test(n2);}


(2)计算2个数并返回 getSum函数

//第二题#includeint getSum(int n1,int n2){return n1+n2;}void main(){int res=getSum(1,9);//传入1 和 9 printf("\nres = %d",res);// res = 10}

(二)、函数调用规则

1.当调用(执行)一个函数时,就会开辟一个独立的空间(栈)。
2.每个栈空间是相互独立
3.当函数执行完毕后,会返回到调用函数位置,继续执行。
4如果函数有返回值,则将返回值赋给接收的变量。
5.当一个函数返回后,该函数对应的栈空间也就销毁

举例:判断函数调用是否正确。

案例1

char* getSum(int num1,int num2){int res = num1 + num2;retuen res; }

错误原因是类型不匹配(char* 到 int)。

案例2

int getSum(int num1,int num2){int res = num1 + num2;retuen res; }

正确,int 到 int。

案例3

int getSum(int num1,int num2){int res = num1 + num2;retuen 0.0; }

可以运行,但是会有警告 double 到 int 有精度损失。

案例4

int getSum(int num1,int num2){int res = num1 + num2;retuen (int)0.0; }

正确,因为有强制转换

案例5

double getSum(int num1,int num2){int res = num1 + num2;retuen res; }

正确,精度小的转精度大的自动转换。

二、函数的递归调用

(一)、递归调用:一个函数在函数体内又调用了本身。

案例:在一个函数在函数体内又调用了本身。

#includevoid test(int n){if(n>2){test(n-1);printf("n=%d\n",n);}}void main(){test(9);}

(二)、函数递归需要遵守的重要原则

(1)执行一个函数时,就创建一个新的受保护的独立空间(新函数栈)。
(2)函数的局部变量是独立的,不会相互影响。
(3)递归必须向退出递归的条件逼近,否则就是无限递归。
(4)当一个函数执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁。

递归练习题

1.斐波那契数

请使用递归的方式,求出斐波那契数1,1,2,3,5,8,13…
给你一个整数n,求出它的斐波那契数是多少。(比如输入7,输出13)

分析:第1,2个数输出1,第3个=第2个+第1个数,…,第n个=第n-1 +第n-2。

#includeint test(int n){if(n==1 || n==2){return 1;}else{return test(n-1) + test(n-2);}}void main(){int m;scanf("%d",&m);int res = test(m);printf("\nres = %d",res);}

2.求函数值

己知 f(1)=3;f(n)= 2*f(n-1)+1;请使用递归的思想编程,求出f(n)的值。(比如输入15,输出65535)

#includeint test(int n){if(n==1){return 3;}else{return 2*test(n-1) + 1;}}void main(){int m;scanf("%d",&m);int res = test(m);printf("\nres = %d",res);}

3.猴子吃桃问题

有一堆桃子,猴子第一天吃了其中的一半,并再多吃了一个!以后每天猴子都吃其中的一半,然后再多吃一个。当到第十天时,想再吃时(还没吃),发现只有1个桃子了。问题:最初共多少个桃子。

分析:
day=10,1个桃子。
day=9, (day10+1)*2 = (1+1)*2=4
day=8,(day9+1)*2 =(4+1)*2=10

#includeint test(int day){if(day==10){return 1;}else{return (test(day+1) + 1)*2;}}void main(){int m;scanf("%d",&m);int res = test(m);printf("\nres = %d",res);}

三、函数注意事项和细节讨论

(1)函数的形参列表可以是多个。
(2)C语言传递参数可以是值传递〈pass by value),也可以传递指针(a pointer passed by value)也叫引用传递。
(3)函数的命名遵循标识符命名规范,首字母不能是数字,可以采用驼峰法或者下划线法,比如getMax()。
(4)函数中的变量是局部的,函数外不生效。

#includevoid f1(int n){n++;//函数中的变量是局部的,函数外不生效。printf("\nf1中的 n=%d",n);//函数中的是 10 } void main(){int n = 9;//还是 9 f1(n);printf("\nmain中 n=%d",n);}


(5)基本数据类型默认是值传递的,即进行值拷贝。在函数内修改,不会影响到原来的值。(如上面例子)
(6)如果希望函数内的变量能修改函数外的变量,可以传入变量的地址&,函数内以指针的方式操作变量。从效果上看类似引用(即指针传递)。

#includevoid f1(int*n){(*n)++;} void main(){int n = 9;f1(&n);printf("\nmain中 n=%d",n);//10}


(7)C语言不支持函数重载。
(8)C语言支持可变参数函数。

习题

请编写一个函数swap(int nl, intn2)可以交换nl 和 n2的值。

#includevoid swap(int*n1,int*n2){int temp = *n1;//将 n1 这个指针指向的变量赋值给 temp*n1 = *n2;*n2 = temp; }void main(){int n1=10,n2=20;swap(&n1,&n2);printf("n1=%d n2=%d",n1,n2);}