多参数函数(可变参数函数)详细剖析

剖析可变参数函数

如何使用可变参数

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设置无效
}
为什么第一个变量的地址上移,就能获取下一个数据?

首先要了解,函数传入形参时是先拷贝一份变量压入栈结构再调函数的,函数变量创建是依照参数表从右往左,这里你需要懂一个概念叫栈帧(不懂的同学可以看我以前的博客,点击即可)
当然如果你赶时间的话,可以看下面的图,我建议先看懂栈帧再来理解比较好

jo-qzy的博客

对应宏变量代码定义

#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);//递归打印数字的每一个数
}
如果你有好方法修改print函数的输出数字部分,还请不吝赐教,感谢看我的博客的每一位访客
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值