可变参数
c语言中实现可变参数列表
我们c语言中实现一个函数时我们会根据需要为它设计参数,当我们调用函数时必须给他对应的参数,不然就会出错。那我们如果参数个数不能确定,又必须要实现这个函数该怎么办呢?
如题:
实现一个函数求一组数(个数不定)的平均数
传参数,第一个参数为数的个数,后面每个为每个数的值
例如:average(3,1,2,6) 输出3。
那这就要依靠可变参数来实现了
语法格式
刚才求平均数的功能可以这样实现
#include <stdio.h>
#include <stdarg.h>
int average(int n,...)
{
va_list argc;
int i = 0;
int sum = 0;
va_start(argc,n);
for(i = 0; i<n; i++)
{
sum += va_arg(argc,int);
}
va_end(argc);
return sum/n;
}
int main()
{
int ret = average(3,1,2,6);
printf("%d\n",ret);
return 0;
}
这样就可以实现刚才的功能了,但是大家可能看不懂,接下来先让大家明白意思再做详细解析
- int average(int n,…) 要注意后面的三个点不是省略号,是英文的句号。
- va_list ——获取不确定个数的参数
- va_start( ) ——指针指向可变参数第一个
- va_arg( ) ——通过地址寻找每个可变参数
- va_end( ) ——指针作废防止崩溃
我们现在只是明白了他的意思,现在我们通过原码来深度理解。
通过原码深度理解
va_list
可见其实va_list 相当于 char * 就是一个字符指针
va_start(argc,n)
他的作用就是取到 n 的地址并将 n 的大小取整后加上
我们知道函数在栈中开辟空间站由高地址向低地址使用
就是将arg指向了第一个可变参数的地址。
va_arg(argc,int);
通过地址取到第一个可变参,并将指针指向下一个可变参数
va_end(argc);
由上两幅图最后一行可知
就是将argc指针的值改为0即空指针
因为功能已实现完将argc改为空,防止非法访问程序崩溃
帮助理解我门将开始的代码用原码表达的意思来替换
#include <stdio.h>
#include <stdarg.h>
int average(int n,...)
{
char* argc; //va_list argc;
int i = 0;
int sum = 0;
argc = (char*)&n + 4; //va_start(argc,n);
for(i = 0; i<n; i++)
{
sum += (*(int*)((argc +=4)-4));
//sum += va_arg(argc,int);
}
argc = NULL; //va_end(argc);
return sum/n;
}
int main()
{
int ret = average(3,11,22,66);
printf("%d\n",ret);
return 0;
}
值得一提的是
(*(int*)((argc +=4)-4))
argc+=4将指针指向下一个可变参数
后面-4将值依然停留在当前可变参数地址
然后强转(int*)再解引用拿到第一个可变参数。
这短短一行完成三个功能,可见原码的高效。
希望大家基本了解了可变参数的基本用法和它的强大,
学会了它我们就可以模拟实现printf函数了!下一篇博客就讲解模拟它的实现。