主页 > 人工智能  > 

c语言基础第12节《函数的调用》

c语言基础第12节《函数的调用》
c语言基础10 函数 函数的调用 调用方式

①函数语句:

test(); // 对于无返回值的函数,直接调用 int res = max(2,4); // 对于有返回值的函数,一般需要再主调函数中接收被调函数的返回值。

②函数表达式:

4 + max(2,4) scanf("%d",&num) != 1

③函数参数

printf("%d",max(2,4)); // 将max(2,4)的值作为了printf()函数的实参

在一个函数中调用另一个函数具备以下条件:

① 被调用的函数必须是已经定义的函数。

② 若使用库函数,应在本文件开头用 #include 包含其对应的头文件。

③ 若使用自定义函数,自定义函数又在主调函数的后面,则应在主调函数中对被调函数进行声明。声明的作用是把函数名、函数参数的个数和类型等信息通知编译系统,以便于在遇到函数时,编译系统能正确识别函数,并检查函数调用的合法性。

函数的声明

函数调用时,往往要遵循先定义后使用,但如果我们对函数的调用操作出现在函数的定义之前,则需要对函数进行声明。

完整的函数使用分为三部分:

函数声明 int max(int x, int y); // 指明参数类型 int max(int,int); // 省略参数类型

函数声明如果是在同一个文件,一定要定义在文件中所有函数定义的最前面。如果有对应的.h文件,可以将函数的声明抽取到.h中。

函数定义 int max(int x, int y) // 函数定义的时候,不能省略参数的数据类型,参数个数,位置要和函数声明时一致 { return x > y ? x : y; } 函数调用 int main() { printf("%d\n",max(5,3)); return 0; }

函数声明的作用:

是把函数名、函数参数的个数、函数参数的类型和返回类型等信息通知给编译系统,以便于在遇到函数时,编译系统能正确识别函数,并检查函数调用的合法性(C语言规范) 错误演示:被调函数写在了主调函数之后 // 主调函数 int main() { printf("%d\n",add(12,13)); // 此时编译会报编译错误,因为函数没有经过声明,编译系统无法检查函数 的调用的合法性。 } // 被调函数 int add(int x, int y) { return x + y; } 正确演示:被调函数写在了主调函数之前

注意:如果函数的调用比较简单,并且被调函数写在主调函数之前,此时是可以省略函数声明的。

// 被调函数 int add(int x, int y) { return x + y; } // 主调函数 int main() { printf("%d\n",add(12,13)); // 此时编译通过 } 正确演示:被调函数和主调函数不分前后,需要增加被调函数的函数声明

注意:如果涉及函数的相互嵌套调用,或者复杂嵌套调用,此时是无法区分函数的前后的,这就需要函数声明

// 函数声明 int add(int,int); // 等价于:int add(int x,int y); // 主调函数 int main() { // 函数调用 printf("%d\n",add(12,13)); // 此时编译通过 } // 被调函数(函数定义) int add(int x, int y) { return x + y; }

声明的方式:

函数首部加上分号 void fun(int a,float b); 函数首部加上分号,可省略形参名,但不能省略参数类型 void fun(int,float); 函数的嵌套调用

函数不允许嵌套定义,但允许嵌套调用

正确:函数嵌套调用 void a(){..} void b() { a(); } 错误:函数嵌套定义 void a() { void b() { } }

嵌套调用:在被调函数内又主动去调用其他函数,这样的函数调用形式,称之为嵌套调用。

funa(){..} funb(){funa();} main(){funb();} 案例

案例1:

编写一个函数,判断给定的3~100的正整数是否是素数,若是返回1,否则返回0代码: /************************************************************************* > File Name: demo01.c > Author: FPF > Description: 函数案例 > Created Time: 2025年02月20日 星期四 11时44分56秒 ************************************************************************/ #include <stdio.h> /** * 定义一个函数,求素数 * @param n:判断这个数是否是素数 */ int sushu(int n) { int k,i,flag = 1; // 素数:只能被1和自身整除的数,所以我们需要校验的是这个数n是否能被 2~n-1之间的数整除,一旦 出现一次能整除的情况,这个数n就不是素数 for(i = 2; i <= n -1; i++) { if(n % i == 0) { flag = 0; break; } } return flag; } int main(int argc,char *argv[]) { for(int i = 3; i <= 100; i++) { if(sushu(i)==1) { printf("%-4d",i); } } printf("\n"); return 0; }

案例1:

输入四个整数,找出其中最大的数,用函数嵌套来实现,要求每次只能两个数比较代码: /************************************************************************* > File Name: demo01.c > Author: > Description: 需求:函数案例-输入四个整数,找出其中最大的数,用函数嵌套来实现,要求每次只能两 个数比较 > Created Time: 2024年12月06日 星期五 09时29分50秒 ************************************************************************/ #include <stdio.h> // 函数声明 int max_2(int,int); int max_4(int,int,int,int); /** * 2个数求最大值 */ int max_2(int a,int b) { return a > b ? a : b; } /** * 4个数求最大值 */ int max_4(int a,int b,int c,int d) { // 写法1 // int max; // 存储最大值 // max = max_2(a,b); // 求a,b的最大值 // max = max_2(max,c); // 求a,b,c的最大值 // max = max_2(max,d); // 求a,b,c,d的最大值 // return max; // 写法2 return max_2(a,b) > max_2(c,d) ? max_2(a,b) : max_2(c,d); } int main(int argc,char *argv[]) { int a=12,b=44,c=33,d=16,result; result = max_4(a,b,c,d); printf("%d,%d,%d,%d中的最大值是%d\n",a,b,c,d,result); return 0; } 函数的递归调用 递归调用的含义:在一个函数中,直接或者间接调用了函数自身,就称之为函数的递归调用。 // 直接调用 a() → a(); // 间接调用 a() → b() → a(); a() → b() → .. → a();

递归调用的本质:

是一种循环结构,他不同于我们之前所学的while,do…while,for这样的循环结构,这些循环结构是借助于循环变量;而递归调用是利用函数自身实现循环结构,如果不加以控制,很容易产生死循环。

递归调用的注意事项:

递归调用必须要有出口,一定要终止递归(否则就会产生死循环)。对终止条件的判断一定要放在函数递归之前(先判断,再执行)进行函数的递归调用。函数递归的同时一定要将函数调用向出口逼近。 案例

案例1:

递归案例-有5个人坐在一起,

问第5个人多少岁?他说比第4个人大2岁。

问第4个人岁数,他说比第3个人大2岁。

问第3个人,又说比第2个人大2岁。

问第2个人,说比第1个人大2岁。

最后问第1个人,他说是10岁。请问第5个人多大。

代码:

/************************************************************************* > File Name: demo02.c > Author: FPF > Description: 递归案例 > Created Time: 2025年02月20日 星期四 14时21分51秒 ************************************************************************/ #include <stdio.h> /** * 求年龄的递归函数 * @param n 第几个人 */ int age(int n) { // 创建一个变量,存储函数返回值,返回的是每个人的年龄 int c; // 第1个人的年龄是已知的,10岁 if(n == 1) { c = 10; } else if (n > 1) // 只过滤正数,也就是非第1人 { c = age(n-1) + 2; // 当前这个人的年龄 = 上一个人的年龄 + 2 } return c; } int main(int argc,char *argv[]) { printf("%d\n",age(5)); return 0; }

案例2:

求阶乘(n!)代码: /************************************************************************* > File Name: demo03.c > Author: FPF > Description: 递归案例:求阶乘(5的阶乘:5×4×3×2×1) > Created Time: 2025年02月20日 星期四 14时43分45秒 ************************************************************************/ #include <stdio.h> /** * 定义一个函数,用来求n的阶乘 * @param n 上限 */ long fac(int n) { // 定义一个变量,用做这个函数的返回值,也就是乘积 long f; // 出口校验 if(n < 0) { printf("n的范围不能是0以下的数\n"); return -1; } else if(n == 0 || n == 1) { f = 1; // 出口 } else // 递归 { f = fac(n-1) * n; } return f; } int main(int argc,char *argv[]) { int n; printf("请输入一个整数:\n"); scanf("%d",&n); printf("%d的阶乘结果是%ld\n",n,fac(n)); return 0; } 数组做函数参数

​ 当用数组做函数的实参时,则形参应该也要用数组/指针变量来接收(函数实参是数组,形参一定是数组或者指针),注意的是,此次传递并不代表传递了数组中所有的元素数据,而是传递了第一个元素的内存地址(数组首地址),形参接收到这个地址后,则形参和实参就代表了同一个块内存空间,则形参的数据修改会改变实参的。这种数据传递的方式,我们称之为地址传递。

​ 如果用数组作为函数的形参,那么我们提供另一个形参表示数组的元素个数。原因是数组形参代表的仅仅是实际数组的首地址。也就是说形参只获取到了实参数组的第一个元素的地址,并不确定传递了多少个数据。所以提供另一个形参表示数组元素的容量,可以防止在被调函数对实际数组访问时产生的下标越界。举例:

// 定义一个函数,将数组作为形参 void fun(int arr[], int len) // 数组传参,形参只能接收到实参数组的首地址,并不是完整的数组 { // int l = sizeof(arr)/ sizeof(arr[0]); 此时编译报错,因为无法确定arr的实际大小,所以无法通过 sizeof进行计算 for(int i = 0; i < len; i++)// len就是传递过来的实参数组的大小 { printf("%-4d",arr[i]); } printf("\n"); } void main() { int arr[] = {11,22,33,44,55}; int len = sizeof(arr) / sizeof(arr[0]); fun(arr,len); }

​ 但有一个例外,如果是用字符数组做形参,且实参数组中存放的是字符串数据(形参是字符数组,实参是字符串常量)。则不用表示数组元素的个数的形参,原因是字符串本身会自动结束\n ,举例:

// 定义一个函数,将数组作为形参 void fun(char arr[100]) // 数组传参,形参只能接收到实参数组的首地址,并不是完整的数组 { char c; int i = 0; while((c =arr[i])!='\0') { printf("%c",c); i++; } printf("\n"); } void main() { fun("hello"); } 案例

案例1:

有两个数组a和b,各有5个元素,将它们对应元素逐个地相比(即a[0]与b[0]比,a[1]

与b[1]比……)。如果a数组中的元素大于b数组中的相应元素的数目多于b数组中元素大

于a数组中相应元素的数目(例如,a[i]>b]i]6次,b[i]>a[i] 3次,其中i每次为不同的值),则

认为a数组大于b数组,并分别统计出两个数组相应元素大于、等于、小于的个数。

int a[10] = {12,12,10,18,5}; int b[10] = {111,112,110,8,5}; 案例: /************************************************************************* > File Name: demo04.c > Author: FPF > Description: 数组作为函数参数 > Created Time: 2025年02月20日 星期四 16时09分05秒 ************************************************************************/ #include <stdio.h> #define LEN 5 /** * 定义一个函数,实现两个数的比较 * @param x,y 参与比较的两个数字 * @return 比较结果,x > y 返回1; x < y 返回 -1; x == y 返回 0 */ int large(int x, int y) { int flag = 0; if (x > y) flag = 1; else if(x < y) flag = -1; return flag; } int main(int argc,char *argv[]) { // 定义两个数组,循环变量,最大,最小,相等 int a[LEN],b[LEN],i,max=0,min=0,k=0; printf("请给数组a添加5个整数:\n"); for(i = 0; i < sizeof(a)/sizeof(a[0]); i++) { scanf("%d",&a[i]); } printf("\n"); printf("请给数组b添加5个整数:\n"); for(i = 0; i < sizeof(b)/sizeof(b[0]); i++) { scanf("%d",&b[i]); } printf("\n"); // 遍历 for(i = 0; i < LEN; i++) { // 比较两个数组中,同一位置两个元素的大小 int value = large(a[i],b[i]); if(value == 1) max++; // 记录a比b大的次数 else if(value == -1) min++; // 记录a比b小的次数 else k++; // 记录a和b相等的次数 } printf("max=%d,min=%d,k=%d\n",max,min,k); return 0; }

案例2:

需求:编写一个函数,用来分别求数组score_1(有5个元素)和数组score_2(有10个元素)各元素的平均值 。代码: /************************************************************************* > File Name: demo05.c > Author: FPF > Description: 数组作为函数参数 > Created Time: 2025年02月20日 星期四 16时28分25秒 ************************************************************************/ #include <stdio.h> /** * 定义一个函数,用来求数组中个元素的平均值 */ float avg(float scores[],int len) { int i; float aver,sum = scores[0];// 保存平均值和总分 // 遍历数组 for(i = 1; i < len; i++) { sum += scores[i]; } // 求平均分 aver = sum / len; return aver; // return sum / len; 等价于上面写法 } int main(int argc,char *argv[]) { // 准备俩测试数组 float scores1[] = {66,78,86,56,46}; float scores2[] = {77,88,67,78,98,32,78,88,77,39}; printf("这个班的平均分:%6.2f\n",avg(scores1,sizeof(scores1)/sizeof(float))); printf("这个班的平均分:%6.2f\n",avg(scores2,sizeof(scores2)/sizeof(float))); return 0; }
标签:

c语言基础第12节《函数的调用》由讯客互联人工智能栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“c语言基础第12节《函数的调用》