想用好函数应该对函数有一个充分的理解,如果不能充分理解函数,运用起来也会容易产生问题。关于函数的理解大家可以参考这篇博客:函数再理解!。下边就在下边在运用上做一些相关说明。
首先说明在C语言中函数参数的传递都是以传值的方式调用的。要实现在其他语言中看似传址的功能,那么把要操作的数所在的地址这个数当做参数传递就可以了。其实说白了所有的传递都是数的传递,只不过传址传递的是地址数据罢了。就如同所有的数组其实都是一维的,只是为了用的方便人们人为的将其分为了二维和多维的罢了。
我们一般用的函数都是一定的参数和类型,但是例如有时候传递的参数的数量和类型需要用户在运行软件期间获取,那么就需要可变的参数列表了。
可变参数列表是通过stdarg这个宏来实现的。这个宏定义在stdarg.h头文件,同时定义了一个va_list类型和va_start、va_arg、va_end三个宏。在定义的函数声明可如下形式:
<span style="font-size:24px;">函数名(int n_values,…)</span>
其中1、va_start用来初始化,参数为va_list变量名和省略号前最后一个有名参数。2、va_arg用来访问和返回参数,参数为va_list变量名和参数列表的下一个参数类型。3、va_end用来在最后取完所有参数后从函数返回,参数是va_list变量名。
说到递归大家都已经很熟悉,简单的定义就是直接或间接调用自身的函数。但是我们经常拿来说明递归的例子:计算阶乘和斐波那契数列的例子其实并不可以从根本上来说明递归功能的真正目的。
下边就是我们常用来说明递归的例程:用递归实现计算n的阶乘。
<span style="font-size:24px;">/* **用递归方法计算n的阶乘 */ long factorial(int n) { if( n <= 0 ) return 1; else return n * factorial( n - 1 ); }</span>
但是这样用递归是有缺陷的,其中因为其中每次对函数的递归调用都会产生很多运行时开销;其实如果函数在递归调用返回之后不再执行任何任务,那么这个递归函数完全可以用迭代计算来替换,当然前提是需要在可读性和运行开销上做一定的权衡。下边就是上边的程序用迭代方法实现的过程。
<span style="font-size:24px;">long factorial(int n) { int result = 1; while( n > 1 ) { result *= n; n -= 1; } return result; }</span>
其实针对这个例子来看,两者的可读性差不太多,但是后者的运行开销要比前者少很多。由此看来后者要优于前者,但是那么什么时候应该用递归呢?看看下边的这个程序:接受一个整型值(无符号),将其转化为字符打印。
<span style="font-size:24px;">/* ** 接受一个整型值(无符号),转化为字符并打印。 */ #include <stdio.h> void binary_to_ascii( unsigned int value ) { unsigned int quotient; quotient = value / 10; if( quotient != 0 ) binary_to_ascii( quotient ); putchar( value % 10 + '0' ); }</span>这个程序和第一个程序对比可以发现,这个程序中函数在调用自身之后还做了一些其他的操作,而第一个程序则什么也没有做。对比可以发现更能体现递归强大功能的是,在函数中当函数调用自身之后,即在每一层函数被调用返回之后还需要对返回信息做进一步操作的时候更适合用递归。要深入理解这一点需要从根本上理解递归这个东西。
原文地址:http://blog.csdn.net/rcj183419/article/details/45649023