可变参数列表

在函数原型中,列出了函数期望接受的参数,但原型只能显示固定数目的参数。让一个函数在不同的时候接受不同数目的参数是不是可以呢?答案是肯定的,但存在一些限制。
   考虑一个计算一系列值的平均值的函数。如果这些值存储于数组中,这个任务就太简单了,所以为了让问题变得更有趣一些,我们假定它们并不存储于数组中。先来看一个计较差的,也是不太稳定的一个解决方案:

复制代码
 1 //计算指定数目的值的平均值(差的方案)
 2 float average(int n_value,int v1,int v2,int v3,int v4,int v5)
 3 {
 4    float sum=v1;
 5    if(n_values>=2)
 6       sum+=v2; 
 7    if(n_values>=3)
 8       sum+=v3;
 9    if(n_values>=4)
10       sum+=v4; 
11    if(n_values>=5)
12       sum+=v5;
13    return sum/n_values;
14 } 
复制代码

这个函数存在几个问题:首先,它不对参数的数量进行测试,无法检测参数过多的这种情况。不过这个问题容易解决,简单加上测试就是了。其次,函数无法处理超过5个的值。要解决这个问题,你只有在已经很臃肿的代码中再增加一些类似的代码。另外还存在一个更为严重的问题:就是实参数与形参的对应不一定准确。

stdarg宏
可变参数列表是通过宏来实现的,这些宏定义stdarg.h头文件,它是标准库的一部分。这个头文件声明了一个类型va_list和
三个宏——va_start、va_arg、va_end。我们可以声明一个类型为va_list的变量,与这几个宏配合使用,访问参数的值。
下面的程序使用三个宏正确的完成计算指定数目的值的平均值的任务。

复制代码
 1 //指定数量的值的平均值 
 2 #include<stdarg.h>
 3 float(int values,...)
 4 {
 5    va_list   var_arg;
 6    int count;
 7    float sum=0;
 8    
 9    var_start(var_arg,n_values);//准备访问可变参数
10     for(count=0;count<n_values;count+=1) //添加取自可变参数表的值 
11     {
12        sum+=var_varg(var_arg,int);
13     }
14     var_end(var_arg);       //完成处理可变参数
15     return sum/n_values;
16 } 
复制代码




另外一篇

c语言中的可变参数列表

(2010-10-14 10:08:45)

   我想很多人和我一样,当对c语言有了一定了解之后,一定会对printf函数产生好奇,因为它可以接受不确定数目的参数。这是怎么实现的呢?看下它的声明:

    intprintf(const char *fmt, ...);

   这个...表示的是什么,在c语言里面,这个叫做可变参数的声明,...就是说它有不确定个参数,专业术语叫可变参数。我们去看看它的源代码:

    intprintf(const char *fmt, ...)

    {

       int res;

       va_list arg;

       va_start(arg, fmt);

       res = vprintf(fmt, arg);

       va_end(arg);

       return res;

    }

   原来它只是简单的调用vprintf,为了弄清什么是可变参数列表,是不是有必要去深究vprintf的代码呢,完全没有必要。下面我们来写一个求最小值的函数min,不过我们要做的当然与简单的#definemin(a, b) (a < b? a: b)又所不同,我们来实现一个求任意个数的最小值的函数:

    intmin(int n, int m, ...)

    {

       int tmp;

       int res = m;

       va_list arg;

       va_start(arg, m);

       while (--n > 1)

        {

            tmp = va_arg(arg,int);

            if (tmp < res)

                res = tmp;

        }

       va_end(arg);

       return res;

    }

   是不是非常的简单。如何用呢,比如说你要求27,18,23,这三个数的最小值,你只需调用min(4,27,18,23,19),是不是很easy,第一个参数指定的是你需要求最小值的数的个数,后面就是具体的值。下面让我们来看看它是怎么工作的:

    在c语言中

   在进行参数调用时,会从右到左把参数压入栈中,对于min(4,27,18,23,19)的调用,其栈内布局如图1所示,
   c语言中的可变参数列表
    因为我们在min函数中已经设了n,m两个形参,所以最上面的两个参数值也就是4,27可以通过访问n,m直接得到,那么我们如何得到18,23,19这三个参数?这时候就需要va_list,也就是一个指针,我们首先定义一个va_list类型的参数arg,这时候arg指向的内容是不确定的。

    调用va_start(arg,m)将arg(注意arg是一个指针)移动到m的后面,如图2所示,此时arg指向的便是18。因为va_list是系统自定义的,所以我们一般不要直接取值,而是调用va_arg(arg,int),它的返回值是arg指针指向的内容,并且将arg下移一位,int表示的是参数的类型,对于我们来说是int,如图3所示。这样在while循环中我们就可以将所有的参数取出,当然也就可以得到最终的最小值。

   需要注意的时,在退出min函数前,必须调用va_end,否则可能会导致不可预料的结果。
   当然我们的函数只能处理int型的最小值,下面是利用c++中的template写的一个可以处理任意类型的min函数:

    #include<iostream>
    #include<cstdarg>


    usingstd::cout;
    usingstd::endl;


    template<typename type >
    type min(intn, type m, ...)
    {
        type tmp;
        type res = m;
        std::va_list arg;
        va_start(arg, m);
         while(--n > 1)
        {
            tmp = va_arg(arg, type);
            if (tmp < res)
            res = tmp;
         }
        va_end(arg);

        return res;
    }

    int
   main(void)
   {
      cout << min(3, 4, 5, 1)<< endl;
       cout<< min(3, 23.1, 4.5, 100.0)<< endl;
      return 0;
    }



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值