【背景引入】
通过我们前面学习和运用了那么多的函数,你有没有发现,他们有一个特别大的共同点:所有函数的入参都是固定的,也就是形参的个数都是固定的,要么1个,要么没有,要么2个等等,但是我们生活中这种毕竟是“特例”,举个例子:你是老板,卖苹果,你能保证每个顾客来买的苹果的个数是一样的吗?肯定不能!如果要让你用一个函数一劳永逸的解决这种卖苹果的钱数(假设:第一个苹果1毛,第二苹果2毛,第三个苹果3毛),你怎么解决?函数入参你都不确定有几个,要怎么实现函数体呢?你仔细想想,是不是生活中这种不确定的事还挺多的?
【分析与解决】
针对上面的问题,我们很容易想到的就是:那就搞个可以改变入参个数的函数不就行了?磨磨唧唧滴,哈哈,确实如此,就是这样:搞一个可以改变入参个数的函数,参数多了,就多输入几个参数,少了就少输入几个参数,这个数量是由调用函数者决定的,这不是就解决了么。确实,C语言之父丹尼斯-里奇也是这样想的,也确实是这样实现的,我们现在正式进入主题:可变参数函数(va_start, va_arg, va_end) 注意:这可不是"完整"的函数哦,这个是夹在我们实现可变参数函数体中的哦,因为这几个函数你不能单独拿出去用,就像是工厂生产的半成品一样,还需要你的"加工"之后,才能作为可变参数函数使用,而且这几个如果严格来说的话,还是宏,或者叫宏函数,反正明白是通过宏定义实现的就行了,不是真正的函数,就是这个意思(本质不同),来,扯远了,我们步入正题,先看定义,完了再写代码验证,你就明白了,如下:
头文件<stdarg.h>中的说明提供了依次处理含有未知数目和类型的函数变量表的机制。
#include <stdarg.h> void va_start(va_list ap, lastarg); type va_arg(va_list ap, type); void va_end(va_list ap);
假设函数f含有可变数目的变量,lastarg是它的最后一个有名参数,然后在f内说明一个类型为va_list的变量ap,它将依次指向每个变量:
va_list ap;
在访问任何未命名的变量(入参变量)前必须用va_start宏对ap进行初始化:
va_start(ap, lastarg);
此后,宏va_arg的每次执行将产生一个与下一个未命名的变量有相同类型和值的值,它同时还修改ap,以使下一次使用va_arg时返回下一个变量:
va_arg(ap, type);
当所有的变量处理完毕之后,f返回之前,必须调用一次宏va_end:
va_end(ap);
【TestCode】
可以看出,前两次调用都正常,分别输出114和6,符合我们的预期,但是第三次好像错了哦,为什么?因为我们输入的可变参数数量是4个,但是我们只给了2个,我们“欺骗”了vatest函数,但是他要继续走下去哈,所以就给我们来个随机值(不信你运行几次看看,每次结果都不一样哦),所以说么,对于可变参数,我们要“诚实”的运行它,说好几个入参,就给人家几个入参,不然的话,可变参数可不会惯着你,它会给你随机值哦,哈哈
【总结】
1.va_start, va_arg, va_end是宏,是帮助我们实现可变参数函数的工具,缺一不可
2.可变参数函数的入参,第一个入参是表明接下来有几个参数哦
3.若是入参不够的话,可变参数函数会使用随机值哦