程序笔记   发布时间:2022-07-01  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了ANSI C函数原型大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

一、函数原型 1.在ANSIC标准之前,声明函数的方案有缺陷,因为只需要声明函数的类型,不用声明任何参数。下面我们看一下使用旧式的函数声明会导致什么问题。 下面是ANSI之前的函数声明,告知编译器imin()返回int类型的值: intimin(); 然而,以上函数声明并未给出imin()函数的参数个数和类型。因此,如果调用imin()时使用的参数个数不对或类型不匹配,编译器根本不会察觉出来。 2.解决办法 C标准要求在函数声明时还要声明变量 的类型,即使用函数原型(functionprototype)来声明函数的返回类型、参数的数量和每个参数的类型。未标明imax()函数有两个int类型的参数,可以使用下面两种函数原型来声明: intimax(int,int); intimax(inta,intb); 第1种形式使用以逗号分隔的类型列表,第2种形式在类型后面添加了变量名。注意,这里的变量名是假名,不必与函数定义的形式参数名一致。有了这些信息,编译器可以检查函数调用是否与函数原型匹配。参数的数量是否正确?参数的类型是否匹配?以imax()为例,如果两个参数都是数字,但是类型不匹配,编译器会把实际参数的类型转换成形式参数的类型。 例如,imax(3.0,5.0)会被转换成imax(3,5) 3.无参数和未指定参数 假设有下面的函数原型: void print_name(); 一个支持ANSIC的编译器会假定用户没有用函数原型来声明函数,它将不会检查参数。为了表明函数确实没有参数,应该在圆括号中使用void关键字: void print_name(void); 支持ANSIC的编译器解释为print_name()不接受任何参数。然后在调用该函数时,编译器会检查以确保没有使用参数。一些函数接受(如,printf()和scanf())许多参数。例如对于printf(),第1个参数是字符串,但是其余参数的类型和数量都不固定。对于这种情况,ANSIC允许使用部分原型。例如,对于printf()可以使用下面的原型: intprintf(constchar,...); 这种原型表明,第1个参数是一个字符串,可能还有其他未指定的参数。C库通过stdarg.h头文件提供了一个定义这类(形参数量不固定的)函数的标准方法。 4.函数原型的优缺点 (1)函数原型是C语言的一个强有力的工具,它让编译器捕获在使用函数时可能出现的许多错误或疏漏。如果编译器没有发现这些问题,就很难觉察出来。是否必须使用函数原型?不一定。你也可以使用旧式的函数声明(即不用声明任何形参),但是这样做的弊大于利。 (2)有一种方法可以省略函数原型却保留函数原型的优点。首先要明白,之所以使用函数原型,是为了让编译器在第1次执行到该函数之前就知道如何使用它。因此,把整个函数定义放在第1次调用该函数之前,也有相同的效果。此时,函数定义也相当于函数原型。对于较小的函数,这种用法很普 遍: //下面这行代码既是函数定义,也是函数原型 intimax(inta,intb){returna>b?a:b;} intmain() { intx,z; ... z=imax(x,50); ... } 二、递归函数 1.定义

(1)C允许函数调用它自己,这种调用过程称为递归(recursion)。 (2)递归由两部分构成:函数关系和出口递归有难以捉摸,有时却很方便实用。结束递归是使用递归的难点,因为如果递归代码中没有终止递归的条件测试部分,一个调用自己的函数会无限递归。可以使用循环的地方通常都可以使用递归。有时用循环解决问题比较好,但有时用递归更好。递归方案更简洁,但效率却没有循环高。 2.递归的两个必要条件 (1)存在限制条件,当满足这个条件时,递归便不再继续。 (2)每次递归调用之后越来越接近这个限制条件。 3.演示递归 /recur.c--递归演示/

include<stdio.h>@H_489_5@

voidup_and_down(int); intmain(void) { up_and_down(1); return0; } voidup_and_down(intn) { printf("Level%d:nLOCATIOn%pn",n,&n);//#1 if(n<4) up_and_down(n+1); printf("LEVEL%d:nLOCATIOn%pn",n,&n);//#2 } 下面是在我们系统中的输出: Level1:nLOCATIOn0x0012ff48 Level2:nLOCATIOn0x0012ff3c Level3:nLOCATIOn0x0012ff30 Level4:nLOCATIOn0x0012ff24 LEVEL4:nLOCATIOn0x0012ff24 LEVEL3:nLOCATIOn0x0012ff30 LEVEL2:nLOCATIOn0x0012ff3c LEVEL1:nLOCATIOn0x0012ff48 我们来仔细分析程序中的递归是如何工作的。首先,main()调用了带参数1的up_and_down()函数,执行结果是up_and_down()中的形式参数n的值是1,所以打印语句#1打印Level1。然后,由于n小于4 up_and_down()(第1级)调用实际参数为n+1(或2)的up_and_down()(第2级)。于是第2级调 用中的n的值是2,打印语句#1打印Level2。与此类似,下面两次调用打印的分别是Level3和Level4。当执行到第4级时,n的值是4,所以if测试条件为假。up_and_down()函数不再调用自己。第4级调用接着执行打印语句#2,即打印LEVEL4,因为n的值是4。此时,第4级调用结束,控制被传回它的主调函数(即第3级调用)。在第3级调用中,执行的最后一条语句是调用if语句中的第4级调用。被调函数(第4级调用)把控制返回在这个位置,因此,第3级调用继续执行后面的代码,打印语句#2打印LEVEL3。然后第3级调用结束,控制被传回 第2级调用,接着打印LEVEL2,以此类推。 注意,每级递归的变量n都属于本级递归私有。这从程序输出的地址值 可以看出(当然,不同的系统表示的地址格式不同,这里关键要注意,Level1和LEVEL1的地址相同,Level2和LEVEL2的地址相同,等等)。 如果觉得不好理解,可以假设有一条函数调用链——fun1()调用 fun2()、fun2()调用 fun3()、fun3()调用fun4()。当 fun4()结束时,控制传回 fun3();当fun3()结束时,控制传回 fun2();当fun2()结束时,控制传回 fun1()。递归的情况与此类似,只不过fun1()、fun2()、fun3()和fun4()都是相同的函数。 4.递归原理 第1,每级函数调用都有自己的变量。也就是说,第1级的n和第2级的n不同,所以程序创建了4个单独的变量,每个变量名都是n,但是它们的值各不相同。当程序最终返回up_and_down()的第1级调用时,最初的n仍然是它的初值1 第2,每次函数调用都会返回一次。当函数执行完毕后,控制权将被传回上一级递归。程序必须按顺序逐级返回递归,从某级up_and_down()返回上一级的up_and_down(),不能跳级回到main()中的第1级调用。 第3,递归函数中位于递归调用之前的语句,均按被调函数的顺序执 行。例如,程序清单9.6中的打印语句#1位于递归调用之前,它按照递归的顺序:第1级、第2级、第3级和第4级,被执行了4次。 第4,递归函数中位于递归调用之后的语句,均按被调函数相反的顺序执行。例如,打印语句#2位于递归调用之后,其执行的顺序是第4级、第3级、第2级、第1级。递归调用的这种特性在解决涉及相反顺序的编程问题时很有用。稍后将介绍一个这样的例子。 第5,然每级递归都有自己的变量,但是并没有拷贝函数的代码。程序按顺序执行函数中的代码,而递归调用就相当于又从头开始执行函数的代码。除了为每次递归调用创建变量外,递归调用非常类似于一个循环语句。实际上,递归有时可用循环来代替,循环有时也能用递归来代替。最后,递归函数必须包含能让递归调用停止的语句。通常,递归函数都使用if或其他等价的测试条件在函数形参等于某特定值时终止递归。为此, 每次递归调用的形参都要使用不同的值。例如,程序up_and_down(n)调用up_and_down(n+1)。最终,实际参数等于4时,if的测试条件(n<4)为假。 5.递归的本质 在传递的过程将问题化简 归一的过程将化简的问题解决 6.递归的应用 (1).问题的定义是按递归定义的(Fibonacci函数,阶乘,…); (2)问题的解法是递归的(有些问题只能使用递归方法来解决,例如,汉诺塔问题,…); (3).数据结构是递归的(链表、树等的操作,包括树的遍历,树的深度,…) 最简单的递归形式是把递归调用置于函数的末尾,即正好在return语句 之前。这种形式的递归被称为尾递归(tailrecursion),因为递归调用在函 数的末尾。尾递归是最简单的递归形式,因为它相当于循环。 下面要介绍的程序示例中,分别用循环和尾递归计算阶乘。一个正整数 的阶乘(factorial)是从1到该整数的所有整数的乘积。例如,3的阶乘(写 作3!)是1×2×3。另外,0!等于1,负数没有阶乘。程序清单9.7中,第1个 函数使用for循环计算阶乘,第2个函数使用递归计算阶乘。 递归实战 (1)阶乘 阶乘递归解法

define _CRT_SECURE_NO_WARNINGS@H_489_5@

include<stdio.h>@H_489_5@

int factorial(int X) // 递归体 { if (x == 1)// 函数出口 { return 1; } return x * (factorial(x - 1));//就x!转换成X*((x-1)!) 达到传递化简的目的 } int main() { int i = 0; scanf("%d", & i); int k = factorial(i); printf("%d", k); return 0; } (2)斐波拉契数列 斐波拉契数列 即0、1、1、2、3、5、8、13、21、34、………这样一串数字 斐波拉契数列递归解法 递归解法通过数学函数定义可轻松得到 他的递归体是当n>1时 fib(n-2)+fib(n-1) 递归出口就是n=0 0,n=1,返回1

define _CRT_SECURE_NO_WARNINGS@H_489_5@

include<stdio.h>@H_489_5@

int fib(int X) //第0个元素为0 第一个元素为1 { if (x == 0) { return 0;

} else if (x == 1) //出口 { return 1; } else return fib(x - 2) + fib(x - 1); //循环体 }

int main() { int k = 0; scanf("%d", &k); int sum = fib(k); printf("%d", sum); return 0; }

大佬总结

以上是大佬教程为你收集整理的ANSI C函数原型全部内容,希望文章能够帮你解决ANSI C函数原型所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。