剖析可变参数函数
如何使用可变参数
void Avg(int num,...)
{
int * ip//要用取出来的数,肯定需要指针来取,这个是求平均数,就定个int吧
va_list ptr;//创建char*指针变量p,这句话相当于char* ptr;
va_start(ptr, num);//将指向num的指针地址存入ptr
{
......
//自行操作取出来的数,用完了再执行下面的指令
ip = va_arg(ptr, type)//ptr地址上移一次
//这里的type需要写入一个类型,是int还是float还是char*将其类型属性给ptr
}
va_end(ptr);//结束使用ptr,将ptr设置无效
}
为什么第一个变量的地址上移,就能获取下一个数据?
首先要了解,函数传入形参时是先拷贝一份变量压入栈结构再调函数的,函数变量创建是依照参数表从右往左,这里你需要懂一个概念叫栈帧(不懂的同学可以看我以前的博客,点击即可)
当然如果你赶时间的话,可以看下面的图,我建议先看懂栈帧再来理解比较好
对应宏变量代码定义
#define va_start __crt_va_start
#define va_arg __crt_va_arg
#define va_end __crt_va_end
#define _INTSIZEOF(n) ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1))
//获取n的类型占几个字节
#define __crt_va_start_a(ap, v) ((void)(ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v)))
//初始化指针,并强转类型赋予指针ap
#define __crt_va_arg(ap, t) (*(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))
//指针向上移动,移动大小根据类型决定
#define __crt_va_end(ap) ((void)(ap = (va_list)0))
//设置指针无效
实例应用
同以前一样,你可以前往我的github下载我的下述代码
这里我自己写了几个函数,分别是:
求几个数平均值函数
求几个数最大值函数
模拟实现printf函数
#define _CRT_SECURE_NO_WARNINGS 1
//1.使用可变参数,实现函数,求函数参数的平均值。
//2.使用可变参数,实现函数,求函数参数的最大值。
//3.模拟实现printf函数,可完成下面的功能:
//print("s ccc d.\n","hello",'b','i','t',100);
#include <stdio.h>
#include <stdarg.h>
int Avg(int n, ...);//求平均数
int Max(int n, ...);//求最大值
int print(char *p, ...);//模拟实现printf
void print_num(int num);//打印数字函数,配合print使用
int main()
{
int n = 6;
printf("平均值函数:%d\n", Avg(n, 5, 7, 8, 9, 10, 3));
printf("最大值函数:%d\n", Max(n, 5, 7, 8, 9, 10, 3));
print("字符串输出测试:字符串:%s\n 字符:%c%c%c\n 数字:%d\n", "hello", 'b', 'i', 't', 100);
system("pause");
return 0;
}
int Avg(int n, ...)
{
int i = 0;
int sum = 0;
va_list ptr;//定义一个char*的指针ptr
va_start(ptr, n);//初始化指针位置,指针指向参数列表第一个参数也就是n
for (i = 0; i < n;i++)
{
sum = sum + va_arg(ptr,int);//获取下一个数据
}
va_end(ptr);
return sum / n;
}
int Max(int n, ...)
{
int max = 0;
int i = 0;
va_list ptr;
va_start(ptr, n);
max = va_arg(ptr, int);
for (i = 1; i < n; i++)
{
int tmp = va_arg(ptr, int);
if (max < tmp)
max = tmp;
}
va_end(ptr);
return max;
}
int print(char *p, ...)
{
char *q = NULL;
int count = 0;
va_list cha;
va_start(cha, p);
while (*p != '\0')
{
if (*p == '%')
{
p++;
switch (*p)
{
case 's'://输出字符串
q = va_arg(cha, char *);
while (*q != '\0')
{
putchar(*q);
q++;
count++;
}
break;
case 'c'://输出字符
putchar(va_arg(cha, char));
count++;
break;
case 'd':
print_num(va_arg(cha, int));//引入一个print函数递归打印数字每一位
break;
case ' '://空格
putchar(' ');
break;
case '\n'://换行
putchar('\n');
break;
default:
break;
}
}
else
putchar(*p);
p++;
}
va_end(cha);
return count;
}
void print_num(int num)//引入一个打印数字的函数
{
if (num > 9)
{
print_num(num / 10);
}
putchar((num % 10) + 48);//递归打印数字的每一个数
}