【C语言】—— 可变参数列表

C语言中的可变参数是一种特殊的函数参数,允许在函数定义中传递可变数量的参数。使用可变参数机制可以使函数更加灵活,可以根据不同的需求接受不同数量或类型的参数。

 

目录

(一)概念理解 

(二)代码展示

1、求和问题

2、求max值

 总结


(一)概念理解 

C语言提供了 <stdarg.h> 头文件,其中包含一组宏来处理可变参数。以下是使用可变参数的详细步骤:

  • 定义函数原型:在函数原型中,使用省略号 ... 表示函数参数的可变部分
void functionName(int fixed_arg, ...);
  • 在函数定义中声明 va_list 类型的变量和一个标识符:
#include <stdarg.h>

void functionName(int fixed_arg, ...)
{
    va_list variable_arguments;  // 可变参数列表的变量
    type arg;                    // 参数标识符
}

当我们到编译器中去查看时,我们不难发现 va_list 就是一个 char类型的指针而已

 

  • 使用 va_start 宏开始访问可变参数列表:
#include <stdarg.h>

void functionName(int fixed_arg, ...)
{
    va_list variable_arguments;
    va_start(variable_arguments, fixed_arg);
}

【说明】 

  • va_start 宏接受两个参数,第一个参数是 va_list 类型的变量;
  • 第二个参数是固定参数的最后一个参数名。 

同样的,在编译器中我们可以去查看背后的定义:

  •   这个宏比较好理解,结合栈帧中临时参数的压入位置

  • 使用 va_arg 宏获取每个可变参数的值,并按照相应的类型进行处理:

 

#include <stdarg.h>

void functionName(int fixed_arg, ...)
{
    va_list variable_arguments;
    va_start(variable_arguments, fixed_arg);

    type arg = va_arg(variable_arguments, type);
}

【说明】  

  • va_arg 宏接受两个参数,第一个参数是 va_list 类型的变量;
  • 第二个参数是可变参数的类型。 

我们也可以在编译器下进行查看定义的操作:

 

分析: 

  1.  这个函数的设计十分的巧妙,先让ap指向下个元素,然后使用【相对位置-偏移量】,访问当前元素;
  2. 访问了当前元素的同时,还让ap 指向下个位置的元素

  • 使用 va_end 宏结束可变参数的访问:
#include <stdarg.h>

void functionName(int fixed_arg, ...)
{
    va_list variable_arguments;
    va_start(variable_arguments, fixed_arg);

    // 使用 va_arg 获取和处理参数值

    va_end(variable_arguments);
}

【说明】

  • va_end 宏接受一个参数,即 va_list 类型的变量名。

同样的,我们同样可以在编译器下查看对应的定义:

 

  • 这个就很好理解了,将ap指向为null

除了上述之外,最难以理解的可能就是以下这个宏函数了:

【说明】

 

 

 使用上述步骤,可以在函数中访问并处理可变数量的参数。需要注意的是,可变参数的传递方式是靠堆栈的,因此调用函数时需确保提供的参数与函数定义中的参数一致,否则会导致未定义行为。


(二)代码展示

1、求和问题

下面是一个使用可变参数的简单示例代码:

#include <stdio.h>
#include <stdarg.h>

// 可变参数函数,计算可变参数的和
int sum(int count, ...)
{
    int total = 0;

    // 声明可变参数列表
    va_list args;
    va_start(args, count);

    // 遍历可变参数并求和
    for (int i = 0; i < count; i++)
    {
        int num = va_arg(args, int);  // 获取下一个可变参数的值
        total += num;
    }

    va_end(args);  // 结束可变参数的访问

    return total;
}

int main()
{
    int result1 = sum(3, 10, 20, 30);
    printf("Sum 1: %d\n", result1);

    int result2 = sum(5, 1, 2, 3, 4, 5);
    printf("Sum 2: %d\n", result2);

    return 0;
}

【说明】

  1. 在上述代码中,我们定义了一个可变参数函数 sum,它可以接受不定数量的整数参数并返回它们的总和;
  2. main 函数中,我们分别调用了 sum 函数两次。第一次传递了 3 个参数,分别是 10、20 和 30;
  3. 第二次传递了 5 个参数,分别是 1、2、3、4 和 5。每次调用后,我们将计算得到的总和打印出来。

运行上述代码,输出结果如下:

 

2、求max值

当涉及到求一组数字中的最大值时,可变参数非常适合使用。以下是一个使用可变参数求最大值的例子:

int find_max(int count, ...)
{
    int max_value = 0;

    va_list args;  // 定义可变参数列表
    va_start(args, count);  // 初始化可变参数列表

    for (int i = 0; i < count; i++)
    {
        int num = va_arg(args, int);  // 获取可变参数列表中的当前整数

        if (i == 0 || num > max_value)
        {
            max_value = num;
        }
    }

    va_end(args);  // 结束可变参数列表

    return max_value;
}

int main()
{
    printf("最大值为:%d\n", find_max(5, 3, 7, 2, 9, 5));  // 输出:9
    printf("最大值为:%d\n", find_max(3, 10, 30, 20));     // 输出:30
    printf("最大值为:%d\n", find_max(1, 100));            // 输出:100
    printf("最大值为:%d\n", find_max(0));                 // 输出:0

    return 0;
}

【说明】

  1. 在上述示例中,我们定义了一个 find_max 函数来求解最大值。函数中的 count 参数表示可变参数的数量,而 ... 表示可变参数的列表。
  2. 在函数中,我们使用 va_list 来定义可变参数列表,并使用 va_startva_arg 宏来遍历和访问每个可变参数。通过比较当前参数和最大值,我们逐步更新最大值。最后,我们使用 va_end 宏来结束可变参数列表。
  3. main 函数中,我们调用 find_max 函数,并传递不同数量的参数。然后,将返回的最大值打印到控制台上。

运行上述代码,输出结果如下:

此时,如果将参数类型改成 char 类型,求char类型变量中的最大值,上述求 max 的逻辑代码后还会有问题吗?

如果将参数类型改为 char 类型,上述的逻辑代码仍然可以工作,但最大值的比较可能会出现问题。这是因为 char 类型在 C 语言中被视为整数类型,而不是字符类型。

  • 代码如下:

int find_max(int count, ...)
{
    int max_value = 0;

    va_list args;  // 定义可变参数列表
    va_start(args, count);  // 初始化可变参数列表

    for (int i = 0; i < count; i++)
    {
        int num = va_arg(args, int);  // 获取可变参数列表中的当前整数

        if (i == 0 || num > max_value)
        {
            max_value = num;
        }
    }

    va_end(args);  // 结束可变参数列表

    return max_value;
}

int main()
{
    
    char a = '1'; //ascii值为:49
    char b = '2'; //ascii值为:50
    char c = '3'; //ascii值为:51
    char d = '4'; //ascii值为:52
    char e = '5'; //ascii值为:53
  

    printf("最大值为:%d\n", find_max(5,a,b,c,d,e));

    return 0;
}

运行上述代码,输出结果如下:

 我们可以发现结果并未收到影响,但是我们解析的时候是按照 va_arg(arg,int) 来解析的?

  1. 因为即使将参数类型改为 char 类型,上述逻辑代码仍然可以工作,而且结果并未受到影响。这是因为在 C 语言中,char 类型在传递给可变参数函数时会被自动提升为 int 类型。
  2. 当使用 va_arg 宏来解析参数时,确实是按照 va_arg(arg, int) 的方式进行解析,即将参数解析为 int 类型。这是因为可变参数函数在执行时,并不知道参数的具体类型,所以需要通过提供的类型信息来正确解析参数。
  3. 因此,即使我们将参数类型改为 char,在使用 va_arg 解析参数时仍然使用 int 类型,但由于 char类型会被自动提升为 int 类型,所以代码仍然可以正常工作并得到正确的结果。
  4. 综上所述,尽管参数类型被定义为 char 类型,但在解析参数时使用 va_arg(arg, int) 是没有问题的,因为传递的实际参数会自动提升为 int 类型。

 总结

以上便是关于C语言中可变参数的全部知识了。感谢大家的观看与支持!!!

 

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

起飞的风筝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值