函数的定义和调用
-
定义格式
返回值类型 函数名([参数表]){ 函数体; [return 表达式;] }
-
函数的声明
如果在main函数前定义,就不用声明
如果在main函数后定义,需要在main函数前先进行声明#include<stdio.h> float Add(float,float); //函数声明,可以不写参数的名字 int main(){ float a,b; scanf("%f %f",&a,&b); printf("%f",Add(a,b)); return 0; } float Add(float x, float y){ float z; z = x+y; return z; }
-
函数调用
函数调用是指一个函数暂时中断运行,去执行另一个函数的过程
1)函数语句调用方式:用于调用没有返回值的函数
函数名([实参表])
2)函数表达式调用方式:用于调用有返回值的函数
变量名 = 函数名([实参表])
-
函数的返回
函数通过return语句向主调用函数返回一个值
return可以不返回任何内容
没有return 程序也会自动返回
如果函数类型不是void,且没有return语句,就会返回一个不确定的值
如果函数类型与return返回的类型不一致,以函数类型为准
函数的参数传递
- 形参和实参
形参:函数定义时的参数
实参:函数调用时的参数
实参形参在数目、类型和顺序上应一致,占据不同存储单元 - 函数调用的执行过程
- 理解单值传递
每个函数都有自己的变量空间,参数也位于这个空间
形参调用前不占内存空间,调用时对形参分配存储单元并传递实参的值
调用结束后,形参内存单元被释放,实参单元保留并维持原值
形参值的变化不会改变主调函数中实参的值
数组作为函数参数
- 数组名作为函数参数
1)数组名表示的是该数组在内存中存放区域的首地址
2)调用时参数实现地址传递
3)所以对形参数组的修改,就是对实参数组的修改,函数可以不返回数组
4)一维数组做参数时可以省略长度
5)二维数组做参数时不能省略第二维的长度#include<stdio.h> int Re(int array[]){ int tmp; tmp = array[0]; array[0] = array[2]; array[2] = tmp; return 0; } int main(){ int a[]={1,2,3}; int i; Re(a); for(i=0;i<3;i++){ printf("%d",a[i]); //结果是321 } return 0; }
函数的嵌套调用
嵌套调用:在调用一个函数的过程中,又调用另一个函数
C语言不能嵌套定义,但可以嵌套调用
例子:输入一个数字n,求1到n之间所有素数的和
#include<stdio.h>
#include<math.h>
int isprime(int m){
int i,k;
k = sqrt(m);
for(i=2;i<=k;i++){
if(m%i==0) return 0;
return 1;
}
long sum(int n){
// 相加函数
int i;
long s =0;
for(i=2;i<=n;i++){
if(isprime(i)==1){
s = s+i;}}
return s;
}
int main(){
int n;
scanf("%d",&n);
printf("Sum = %ld\n",sum(n));
return 0;
}
函数的递归调用
- 递归调用:在调用一个函数的过程中,又直接或间接地调用该函数本身
- 递归的特点
1)存在递归终止的条件
2)存在导致问题求解的递归方法
3)递归方法:递推、回归等 - 递归的优缺点
1)优点:代码紧凑
2)缺点:每调用一次都要在内存中分配空间,可能引起内存溢出且时间效率差 - 例子:用递归的方法计算n的阶乘
#include<stdio.h> long fact(int n){ long f; if (n==1||n==0) f=1; else f = n*fact(n-1); return f; } int main(){ long y; int n; scanf("%d",&n); y = fact(n); printf("%d!=%ld\n",n,y); return 0; }