函数

C语言函数传参

C 语言中,函数的参数传递方式有两种:传值调用和传址调用。

传值调用

将实参的值复制到形参相应的存储单元中,即形参和实参分别占用不同的存储单元,这种传递方式称为“参数的值传递”或者“函数的传值调用”。

值传递的特点是单向传递,即主调函数调用时给形参分配存储单元,把实参的值传递给形参,在调用结束后,形参的存储单元被释放,而形参值的任何变化都不会影响到实参的值,实参的存储单元仍保留并维持数值不变。

传址调用

这种方式使用数组名或者指针作为函数参数,传递的是该数组的首地址或指针的值,而形参接收到的是地址,即指向实参的存储单元,形参和实参占用相同的存储单元,这种传递方式称为“参数的地址传递”。

地址传递的特点是形参并不存在存储空间,编译系统不为形参数组分配内存。数组名或指针就是一组连续空间的首地址。因此在数组名或指针作函数参数时所进行的传送只是地址传送,形参在取得该首地址之后,与实参共同拥有一段内存空间,形参的变化也就是实参的变化。

递归函数

递归的基本原理

递归函数即自调用函数,在函数内部直接或间接地自己调用自己,即函数的嵌套调用是函数本身。

  • 每一级的函数调用都有自己的变量。
  • 每一次函数调用都会有一次返回。
  • 递归函数中,位于递归调用前的语句和各级被调用函数具有相同的执行顺序。
  • 递归函数中,位于递归调用后的语句的执行顺序和各个被调用函数的顺序相反。
  • 虽然每一级递归都有自己的变量,但是函数代码并不会得到复制。
  • 递归函数中必须包含可以终止递归调用的语句。

递归的优缺点

其优点在于为某些变成问题提供了最简单的解决方法,简化了程序设计。

缺点是一些递归算法会很快耗尽计算机的内存资源。同时,使用递归的程序难于阅读和维护。

基本递归

例如,递归方式计算阶乘:

int fact(int n) {
    if(n < 0)
        return 0;
    else if (n == 0 || n == 1)
        return 1;
    else
        return n * fact(n - 1);
}

以计算4!为例:

归方法中的需要的所有状态通过方法的参数传入下一次调用中。

  • 尾递归是极其重要的,不用尾递归,函数的堆栈耗用难以估量,需要保存很多中间函数的堆栈。

尾递归实现计算阶乘:

int facttail(int n, int a)
{
    if (n < 0)
        return 0;
    else if (n == 0)
        return 1;
    else if (n == 1)
        return a;
    else
        return facttail(n - 1, n * a);
}

可变参数列表

可变参数列表可通过宏来实现,这些宏定义在stdarg.h头文件中,它是标准库的一部分。这个头文件声明了一个类型va_list和三个宏:va_startva_argva_end。可以声明一个类型为va_list的变量,与这几个宏配合使用,访问参数的值。

参数列表的可变部分位于一个或多个普通参数(命名参数)的后面(即参数列表中至少要有一个命名参数),它在函数原型中以一个省略号表示。

例如求平均数:

#include <stdarg.h>

float average(int n_values, ...)
{
	va_list var_argue;
	int count;
	float sum = 0;

	va_start(var_argue, n_values);

	for (count = 0; count<n_values; count++)
	{
		sum += va_arg(var_argue, int);
	}

	va_end(var_argue);
	return sum / n_values;
}
  • 函数声明一个名叫var_argue的变量,它用来访问参数列表的未确定部分。
  • var_argue通过调用va_start来初始化。它的第一个参数是va_list 类型变量的名字,第二个参数是省略号前最后一个有名字的参数。初始化过程把变量var_argue设置为指向可变参数部分的第一个参数。
  • 为了访问参数,需要使用va_arg,这个宏接受两个参数:va_list类型变量和参数列表中下一个参数的类型。在这个例子中,所有的可变参数都是整型。va_arg返回这个参数的值,并使var_arg指向下一个可变参数。
  • 当访问完毕最后一个可变参数之后,需要调用va_end

可变参使用注意事项

  • 参数列表中,至少有一个命名参数,如果连一个命名参数都没有,就无法使用arg_start宏。

  • 可变参数的类型和个数完全由程序代码控制,它并不能智能地识别不同参数的个数和类型。如果在va_arg中指明了错误的类型,其结果是不可预知的。

  • 可变参数只能从头到尾逐个访问,如果你在访问几个参数后想中途退出,这是允许的,但是直接访问参数列表的中间部分是不行的。

posted @ 2019-09-15 10:24  youngliu91  阅读(250)  评论(0编辑  收藏  举报