可变参数列表

在函数原型中,列出了函数期望接受的参数,但原型只能显示固定数目的参数。让一个函数在不同的时候接受不同数目的参数是不是可以呢?答案是肯定的,但存在一些限制。

#include
#include
#include

//利用可变参数列表实现加法。
int add(int num, ...)
{
    int i = 0;
    int sum = 0;
    int tmp = 0;
    va_list arg;//在这定义了一个char 类型的指针。
    va_start(arg, num);//这个的功能是读取所有的参数,从头开始
                      //后读取你所给的参数个数,并且把参数放到指针中。
    for (i = 0; i < num; i++)
    {
        tmp = va_arg(arg, int);//在这,起到的作用是读取所给的参数
        sum += tmp;
    }
    va_end(arg);//结束读取
    return sum;
}

int main()
{
    int ret = 0;
    ret=add(4,5,6,7,5);
    printf("%d", ret);
    system("pause");
    return 0;
}

可变参数列表_第1张图片

要记住下面这些都封装在stdarg.h头文件中。
va_list arg这个说的就是一个char 类型的指针,并且记住地址
va_start(arg,…之前的一个参数) 读取所有的参数,从头开始后读取你所给的参数个数,并且把参数放到指针中。
va_arg (arg,类型)读取参数,挨个读取,返回这个参数的值,并且使得指向下一个可变参数。
va_end(arg) 结束读取。

*C语言中对可变参数的限制

-无法确定可变参数列表的长度。
-不能提供类型检查。

对于关键的宏进行解读

  • 1.va_list
    宏:#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
    这个宏本身只是个定义,真正赋予其意义的在于下面的几个宏。
    实现:实际上只是一个 char * 类型的指针,原因这里不能判定类型,所以用size为1的char类型指针会方便移动。

  • 2.va_start
    宏:#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
    这个宏需要两个参数,第一个是上面定义的 va_list, 第二个是可变参数列表之前的那个参数。
    注意:va_start中的参数,一定要是最后一个参数,也就是…之前的那个参数,不然可能会有问题。尤其是windows和linux的函数参数入栈顺序不同,会有可移植性问题。

  • 3.va_arg
    宏:#define va_arg(ap,t) ( (t )((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
    同样有两个参数,第一个是前面已经初始化好的 va_list,第二个是类型,比如这里可变参数列表的第一个参数是int类型,那么就传int。

  • 4.va_end
    宏:#define va_end(ap) ( ap = (va_list)0 )
    为了更好的可读性,结束可变参数的获取。

可变参数必须从头到尾按照顺序逐个进行访问,如果你在访问几个可变参数后想半途中止,这是可以的,但是不能一开始就访问参数列表中间的参数。

另外需要注意的是,参数列表中至少需要有一个命名参数。命名参数指定了实际传递的参数数量,
接下来,来用可变参数列表实现一个超级厉害的system函数。

#include
#include
#include
#include
void go(int num, ...)
{
    int i = 0;
    va_list arg;
    va_start(arg, num);
    for (i = 0; i < num; i++)
    {
        char arr[20];
        strcpy(arr, va_arg(arg, char *));
        printf("%s", arr);
        system(arr);
    }
    va_end(arg);
}
int main()
{
    go(9,"notepad","calc","tasklist","ipconfig","mspaint","write","title wuyuzhe","color 3e","pause");
}

可变参数列表_第2张图片
可变参数列表_第3张图片
可变参数列表_第4张图片

在这里通过这个超级厉害的system函数可以实现打开记事本,计算器,查看进程,查询ip,画图工具,写字本,然后让命令行程序的标题改成了wuyuzhe,还改了颜色,然后最后执行了暂停。
很好很强大的东西,可以实现很多的指令。

接下来,我们用可变参数列表,实现一个部分printf()函数的功能
print(“s ccc.\n”,”hello”,’b’,’i’,’t’);
print(char *format, …)

#include
#include
#include
void print(char *format, ...)
{
    va_list arg;
    va_start(arg, format);

    while (*format)
    {
        switch (*format)
        {
            case 'c':
            {
                char tmp = va_arg(arg, char);
                putchar(tmp);
            }
                break;
            case 's':
            {
                        char *str = va_arg(arg, char*);
                        while (*str)
                        {
                            putchar(*str);
                            str++;
                        }
            }
                break;
            default:
                putchar(*format);
                break;
        }
        format++;
    }
    va_end(arg);
}
int main()
{
    print("s ccc.\n", "hello", 'b', 'i', 't');
    system("pause");
    return 0;
}

你可能感兴趣的:(C)