可变参数列表

函数原型:列出了函数期望收到的参数数目及类型,但是它只能显示“固定数目”的参数。

可变参数列表:让一个函数在不同的时刻接受“不同数目”的参数。可变参数列表是通过宏来实现的,这些宏都在stdarg.h这个头文件中,所以使用可变参数列表时要引用头文件#include<stdarg>。

例如:求寻找一组整数中最小的值,因为整数的个数不确定,所以函数在传参的时候也是不确定的,因此需要用到可变参数列表:

利用可变参数列表求最小值:来看看可变参数列表的形式:

int min_num(int val, ...)

{

va_list arg;

va_start(arg, val );

int min = va_arg (arg, int);

for (int i = 0; i < val; i++)

{

int tmp = va_arg (arg, int);

if (min>tmp)

min = tmp;

}

va_end(arg);

return min;

}

int main()

{

int ret=min_num(5,1,0,2,4,5);

printf( "%d\n", ret);

system( "pause");

return 0;

}

分析:

int min_num(int val, ...)

//注意可变参数列表至少要有一个参数,这是因为你要通过这个参数的地址才能访问后面的参数,而这个参数就叫做命名参数(也就是“ ... ”前面的参数)

va_list arg;

//va_list 是一个char *类型(typedef  char *  va_list),声明一个char *类型的指针,便于向后访问.

va_start(arg, val );

//初始化arg,可以看到,va_start有两个参数,一个是va_list所声明的指针arg,另一个参数列表中第一个参数 val.

通过:#define _crt_va_start (ap,v)  ( ap = (va_list) _ADDRESSOF(v) + _INTSIZEOF (v) )

看出,va_start的功能就是让指针arg向后偏移sizeof(val)个大小,即让arg指向参数列表中val之后的下一个参数的位置。(va_start(arg,val)实际上是让指针arg指向参数列表中第一个可变参数,所以va_start的第二个参数应该是“    ...   ”的前一个参数,因为本题中“  ...   ”前面只有一个参数val,所以va_start的第二个参数是val).

int min = va_arg (arg, int);

//va_arg(arg,int)      用来获取参数,即va_start(arg,int)表示的就是*arg;

通过:#define _crt_va_arg (ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

(ap += _INTSIZEOF(t))         - _INTSIZEOF(t)    所表达的意思可以分成两个语句:

第一个语句: ap+=_INTSIZEOF(t)       这时ap已经指向了下一个参数

第二个语句: ap-_INTSIZEOF(t)           整个表达式的值并没有保存,所以整个表达式*引用后指向的还是当前的值。

可以看到每当使用一次ap之后ap都向后偏移sizeof(int)个字节,指向下一个参数。

int tmp = va_arg (arg, int);

//这个也是一样,用来获取参数,但是到什么时候停下来呢???这时候val就派上作用,val代表   “...”中被传递过来实参的个数,例如在本题中,要找出5个数中最小值,val就是5;同理要是在100个数中找,val代表的是100

va_end(arg);

//因为arg是一个指针,所以在使用完后最好将它赋成空。

#define _crt_va_end (ap)      ( ap = (va_list)0 )

va_list;是一个类型代表char *

va_start();初始化arg;实际上是:arg=&val+sizeof(aize_t val),让指针arg找到第一个可变参数

va_arg();获取下一个参数:就是引用*arg,用完之后再让arg加一(注意每使用一次va_arg(),arg都会自动指向下一个可变参数

va_end();将arg赋成0;把指针赋成0.

总结:可变参数列表通过参数之间的地址进行访问

可变参数列表的限制:

1、只能从第一个可变参数一次向后访问(这是移位他实际上是通过前一个参数的地址向后偏移找到下一个参数,依次向后递推着访问

2、因为可变参数列表是通过宏实现的,而宏无法判断参数的类型和可变参数的个数,所以我们必须使用命名参数。

#define _crt_va_start (ap,v)  ( ap = (va_list) _ADDRESSOF(v) + _INTSIZEOF (v) )

#define _crt_va_arg (ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

#define _crt_va_end (ap)      ( ap = (va_list)0 )

例:模拟实现prinf函数,实现:   print(arr, "s ccc.\n","hello" ,‘b‘,‘i‘,‘t‘);

#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h>

char * print(char *arr,char *format, ...)
{
      char *p = arr ;
      va_list arg;
      va_start(arg,format );
      while (*format )
       {
             if (*format == ‘s‘)
             {
                   char *p3 = va_arg (arg, char *);
                     while (*p3)
                     {
                         *p++=*p3++;
                     }
                         p--;
              }                          
               else if (*format == ‘c‘)
                     *p = va_arg(arg, char );
               else
                    *p= *format;
                    
               format++;
               p++;
        }
        *p = ‘\0‘;
        va_end(arg);
        return arr ;
}
int main()
{
       char arr[100];
       print(arr, "s ccc.\n","hello" ,‘b‘,‘i‘,‘t‘);
       printf( "%s",arr);
       system( "pause");
       return 0;
}
时间: 2024-10-23 18:40:07

可变参数列表的相关文章

java可变参数列表的实现

参数就是我们调用一个方法时需要传入得数据,在方法中可能需要参数协助处理数据或者对参数进行解析处理以达到我们希望得到的数据和结果. 平常我们在写一个方法时,我们能确定需要传入什么样的参数以及参数的个数,这样我们在实现这个方法的时候在确定参数的时候都会有明确的目标.但是有时候会有这种特殊情况,我们并不知道我们将要传入几个参数,或者说我们并不确定外部会传入多少参数.在这种情况下,我们就要用到可变参数列表.下面是可变参数方法的实现方法. 1.传入数组对象或者集合,这里只对传入数组对象进行简单说明,集合的

可变参数列表的实现

在学习C语言的过程中,大家是不是和我一样,认为printf是一个神一样的函数?他可以接受不同数目,不同类型的参数,他到底是怎么实现的呢? 让我们去看一下它的源代码: printf源代码: int printf(const char *fmt,...) { int res; va_list arg; va_start(arg,fmt); res = vprintf(fmt,arg); va_end(arg); return res; } 它采用的是可变参数列表,可变参数列表主要有以下两个缺点: 1

【C语言】求多个数中的最大值(可变参数列表)

求多个数中的最大值要求用可变参数列表: 代码如下: <span style="font-size:18px;">#include<stdio.h> #include<stdarg.h> int Max(int n,...) { int i=0; int max=0; va_list arg; va_start(arg,n); for(i=0;i<n;i++) { int val=va_arg(arg,int); if (val>max)

PHP函数可变参数列表的具体实现方法介绍

PHP函数可变参数列表可以通过_get_args().func_num_args().func_get_arg()这三个函数来实现.我们下面就对此做了详细的介绍. AD:2014WOT全球软件技术峰会北京站 课程视频发布 也许对于PHP初级程序员来说,对于PHP函数并不能完全熟练的掌握.我们今天为大家介绍的PHP函数可变参数列表的实现方法主要是利用func_get_args().func_num_args().func_get_arg()这三个系统函数来实现的,其中func_get_args()

C语言函数可变参数列表

C语言允许使用可变参数列表,我们常用的printf函数即为可变参数函数,C标准库提供了stdarg.h为我们提供了这方面支持:该头文件提供了一些类型和宏来支持可变参数列表,包括类型va_list,宏va_start.va_arg.va_end: 可变函数参数定义方法: #include <stdarg.h> void func(int count,...){ va_list ap; int ix, tmp; va_start(ap, a); for(ix=0;ix < count; ++

【转】C++可变参数列表处理宏va_list、va_start、va_end的使用

VA_LIST是在C语言中解决变参问题的一组宏他有这么几个成员: 1)va_list型变量: #ifdef     _M_ALPHA typedef    struct{ char* a0; /*pointertofirsthomedintegerargument*/ int offset; /*byteoffsetofnextparameter*/ }va_list; #else typedef    char* va_list;#endif 2)_INTSIZEOF宏,获取类型占用的空间长度

创建函数利用可变参数列表的形式模拟实现printf的功能

★创建函数利用可变参数列表的形式模拟实现printf的功能. 模拟简单的输入单个字符和字符串时的输出形式 如:输入:%c %c %c %c %c\t%s,'h','e','l','l','o',"welcome to here!" 输出:h e l l o   welcome to here! #include<stdio.h> #include<stdlib.h> #include<stdarg.h>    //需引入stdarg的头文件以便建立可

Java 可变参数列表

1.可变参数列表的简单实现 当调用方法时,方法的参数个数或类型未知时,称其为可变参数列表.在以前的Java代码中,可以使用Object数组来实现这样的功能.因为,所有的类都是直接或间接继承于Object类. VarArgs.java package sample; class A1{} public class VarArgs { static void printArray(Object[] args){ for(Object obj:args) System.out.print(obj+"

浅析可变参数列表的使用

在我们使用函数时,一般大多数情况下里面的参数都是给定的,而且我们一般使用时并不会超过三个参数,可是这并不排除不会出现三个以上的参数,比如说求平均值,求和等等一些可能出现三个以上参数的函数运算,这时我们的参数不再是固定的,而是随时会不断变化的.因此我们就需要一种方法来实现它们,这种方法就是C语言给我们提供的一种叫做可变参数列表的函数方法. 首先,可变参数列表是通过宏来定义的,而这些宏又在<stdarg.h>的头文件中,因此我们在使用时要先引用该头文件,在引用后我们需要其下三个宏的函数: void