可变参数列表问题

  可变参数列表解析及简单应用: 在函数原型中,列出函数期望接受的参数,但是原型只能显示固定数目的参数。通俗来讲就是,当我们给定函数原型时候,我们也就确定了函数的参数的个数,传递参数的时候必须按照原型提供的参数个数来传递参数。
那么我们是否可以传递参数时候,提供可变个参数呢?

当然是可以的,比如我们常用的printf()函数,我们可以用以下方式传递多个参数给此函数。

printf("hello");//一个参数
printf("%d",12);//两个参数
printf("%d%d",12,11);//三个参数

printf函数原型。


可以看到在printf函数参数中有由 “…”组成的参数构成,这是可变函数参数的标准格式,也是标志。我们把参数可变的函数叫做可变参数函数。
可变参数列表是通过宏来实现的,这些宏定义在头文件stdarg.h中,这个头文件中声明了一个类型va_lsit和三个宏——va_start、va_arg、va_end。
解析:
va_list类型:这个类型是通过typedef将char 类型进行了重命名,也就是说va_list是char 类型。
va_start宏:用来初始化,它的第一个参数是va_list变量的名字,第二个参数是省略号前最后一个用名字的参数。初始化过程是把va_list类型的变量设置为指向可变参数部分的第一个参数。
va_arg宏:为了访问参数,需要使用这个宏来实现,这个宏接受两个参数,va_list变量和下一个参数的类型。
va_end宏:使用这个宏来结束访问。


以下是简单实现用可变参数列表来求不同个数参数的平均值。

#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h>
float average(int num, ...)
{
    va_list arg;//声明va_list类型变量arg
    int count;
    float sum = 0;
    va_start(var_arg, num);//初始化变量
    for (count = 0; count < num; count += 1)
    {
        sum += va_arg(arg, int);//访问变量
    }
    va_end(arg);//调用结束
    return sum / num;
}
int main()
{
    float aver = 0.0;
    aver=average(5, 1, 2, 3, 4, 5);
    printf("%f\n", aver);   
    system("pause");    
    return 0;
以下用可变参数列表求最大值。

#include<stdio.h>
#include<stdarg.h>
#include<stdlib.h>
int fun(int num, ...)
{
	va_list arg;
	int i = 0;
	int max = 0;
	int tmp = 0;
	va_start(arg, num);
	max = va_arg(arg, int);
	for (i = 0; i < num - 1; i++)
	{
		tmp = va_arg(arg, int);
		if (tmp>max)
		{
			max = tmp;
		}
	}
	va_end(arg);
	return max;
}
int main()
{
	int max = 0;
	max = fun(5, 1, 2, 3, 4, 5);
	printf("%d\n",max);
	system("pause");
	return 0;
}
可以看到va_list类型实质是char *类型。
而va_start、va_arg、va_end经过宏定义为_crt_va_start、_crt_va_arg、_crt_va_end.
为什么要定义为_crt函数呢?首先我们得了解什么是CRT函数,一般来说,CRT函数就是标准的C语言函数。而可变参数列表是标准库的一部分。
为了对宏定义进行分析说明,我们将宏定义全部替换可得到如下:
先来解释此处的宏定义的作用:
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
_INTSIZEOF(n)整个做的事情就是将n的长度化为int长度的整数倍。
比如n为5,二进制就是101b,int长度为4,二进制为100b,那么n化为int长度的整数倍就应该为8。
~(sizeof(int) - 1) )就应该为~(4-1)=~(00000011b)=11111100b,这样任何数& ~(sizeof(int) - 1) )后最后两位肯定为0,就肯定是4的整数倍了。
(sizeof(n) + sizeof(int) - 1)就是将大于4m但小于等于4(m+1)的数提高到大于等于4(m+1)但小于4(m+2),这样再& ~(sizeof(int) - 1) )后就正好将原长度补齐到4的倍数了。

用可变参数列表打印。“hellow”"bit".

#include <stdio.h>  
#include <assert.h>  
#include <stdarg.h>  
#include <string.h>  
  
int m_printf(const char *str, ...)  
{  
    char *eos = (char *)str;  
    int ret = 0;  
  
    va_list ap;  
    va_start(ap, str);  
  
    assert(str);  
  
    while (*eos)  
    {  
        if('%' == *eos)  
        {  
            int d = 0;  
            char c = 0;  
            char *s = NULL;   
  
            eos++;  
              
            switch(*eos)  
            {  
            case 's':  
                s = va_arg(ap, char*);  
                while(*s)  
                {  
                    putchar(*s);  
                    s++;  
                    ret++;  
                }  
                //不能用puts()->会自动换行  
                //不能用putchar()->会只输出首字母  
                break;  
            case 'c':  
            //  c = va_arg(ap, char);  
            //  printf("%c", c);  
                putchar(va_arg(ap, char));  
                ret++;  
                break;  
            case 'd':  
                d = va_arg(ap, int);  
                printf("%d", d);  
                while(d)  
                {  
                    ret++;  
                    d /= 10;  
                }  
                break;  
            case '\0':  
                putchar('\0');  
            default :  
                ;  
                break;  
            }  
        }  
        else  
        {  
            putchar(*eos);  
            ret++;    
        }  
  
        eos++;  
    }  
  
    va_end(ap);  
  
    return (ret);  
}  
  
int main()  
{  
    char str1[] = "Hello";  
    char str2[] = "bit";  
    int num = 200;  
  
    int ret1 = m_printf("第%d行 : %s %c%c%c\n", 100, "hello",'b','i','t');  
    int ret2 = m_printf("第%d行 : %s %s\n", num, str1, str2);  
    //求解:中文为什么能以%c格式打印出来,而不是%s  
  
    //m_printf(NULL);  
    //试验:当传入空指针时。  
  
    m_printf("ret1 = %d\n",ret1);     
    m_printf("ret2 = %d\n",ret2);  
  
    return 0;  
}  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值