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

news2024/11/19 3:44:38

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语言中可变参数的全部知识了。感谢大家的观看与支持!!!

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/799586.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Games虚拟现实人本计算研究

晚上八点(北京时间)的 GAMES Webinar 《VR/AR专题》第二期即将开始&#xff01;&#x1f525;&#x1f525;&#x1f525; &#x1f4dc;本期主题&#xff1a;VR人本计算及交互 &#x1f468;&#x1f3fb;‍&#x1f3eb;嘉宾1&#xff1a;北京大学的李胜老师 &#x1f468;…

纪录片《打铁文艺社》:从全美高中生电影节到多项国际赞誉,聚焦城市公共艺术的蜕变之路

7月21日&#xff0c;在全美高中生电影节&#xff08;All American High School Film Festival&#xff0c;AAHSFF&#xff09;公布的入围名单中&#xff0c;一部取材于中国深圳的纪录片《打铁文艺社Datie: The Art Tribe of Tiegang》以其深刻的主题和精良的制作&#xff0c;引…

git 合并非关联分支

面对的场景&#xff1a;现在有三个仓库&#xff0c;一个是本地的仓库1&#xff0c;第二个是和仓库1关联的在github上的仓库2&#xff0c;第三个是把仓库1拷贝到一个无网络环境中持续开发一段时间的仓库3. 分析 基本想法是把仓库3作为仓库1的远程仓库&#xff0c;然后在仓库1上…

Clion配置与使用记录

Clion与ROS2、docker 为了能够在Docker中使用ROS2环境&#xff0c;同时Clion能够在编辑代码时可以有代码提示以及函数、变量跳转等功能 Docker配置 参考&#xff1a;Docker SSH配置 启动Docker&#xff0c;需要将端口映射&#xff0c;添加如下参数&#xff1a; -p 8024:22&…

Redis-基于内存的key-value结构数据库

读写性高&#xff0c;适合存储热点性高的数据 也称为结构化的NoSql数据库 redis依赖环境&#xff1a;gcc NoSql 非关系型数据库&#xff0c;是关系型数据库的补充 关系型(RDBMS)非关系型(NoSql)MySqlRedisOracleMongo dbDB2MemCachedSQLServer 常用命令 Redis 教程_redi…

手机中有三个特别耗电的功能,半天就耗掉一半电量,记得关掉

在现代社会&#xff0c;手机已经成为我们生活中不可或缺的伙伴。然而&#xff0c;随着手机功能的日益强大和应用的多样化&#xff0c;电池续航成为了许多人的困扰。您是否曾经经历过使用手机一半时间&#xff0c;电量却已经耗掉一半的情况&#xff1f;若是如此&#xff0c;可能…

Pytorch图像处理注意力机制SENet CBAM ECA模块解读

目录 1. 注意力机制 1.1 SENet&#xff08;Squeeze-and-Excitation Network&#xff09; 1.1.1 SENet原理 1.1.2 SENet代码示例 1.2 CBAM&#xff08;Convolutional Block Attention Module&#xff09; 1.2.1 CBAM原理 1.2.2 CBAM代码示例 1.3 ECA&#xff08;Efficien…

Vue中TodoLists案例_底部统计

与上一篇Vue中TodoList案例_删除有俩个文件变化了 App.vue&#xff1a;向儿子组件MyFooter传递参数todos <template><div id"root"><div class"todo-container"><div class"todo-wrap"><MyHeader :addTodo"add…

每天一道C语言编程(递归:斐波那契数,母牛的故事)

递归的条件 递归函数必须有一个可直接退出的条件&#xff0c;否则会进入无限递归&#xff0c;例如 #include<stdio.h> void f(int n) {if(n<0)return;f(n-1);printf("%d ",n); }int main() {int n5;f(n);return 0;}//递归的出口 if(n<0) retur…

【docker】docker部署nginx

目录 一、步骤二、示例 一、步骤 1.搜索nginx镜像 2.拉取nginx镜像 3.创建容器 4.测试nginx 二、示例 1.搜索nginx镜像 docker search nginx2.拉取nginx镜像 docker pull nginx3.创建容器&#xff0c;设置端口映射、目录映射 # 在root目录下创建nginx目录用于存储nginx数据…

花色更潮的夜光飞盘,手感也很出色

飞盘运动因为易于入门&#xff0c;方便操作&#xff0c;一直以来都备受大家的喜爱&#xff0c;而近几年更是成为了一项非常流行的户外运动。每天玩上一局飞盘&#xff0c;不仅可以锻炼身体&#xff0c;还能够增强团队合作意识&#xff0c;让大家在运动中尽情享受乐趣。 这两天我…

【树上点对问题】Tree Problem

Problem - D - Codeforces 题意&#xff1a; 思路&#xff1a; 一个很裸的树形DP 对于树上的一对点&#xff0c;我们往往考虑更换枚举对象 如果关注的是路径经过边&#xff0c;那么就考虑一条边两端的连通分量 如果关注的是路径经过点&#xff0c;那么分成两部分考虑 一部…

郑州如何为SSL证书续期

SSL数字证书的主要作用就是保护网站传输数据安全&#xff0c;而我们要知道SSL证书是有时间限制&#xff0c;到期之后就会失效&#xff0c;对网站传输数据的加密保护也会失效&#xff0c;这就需要我们在失效前为SSL证书续期。那么我们该如何为SSL证书续期呢&#xff1f;今天随SS…

uniapp实现带参数二维码

view <view class"canvas"><!-- 二维码插件 width height设置宽高 --><canvas canvas-id"qrcode" :style"{width: ${qrcodeSize}px, height: ${qrcodeSize}px}" /></view> script import uQRCode from /utils/uqrcod…

断路器分合闸速断试验

试验目的 高压断路器的分、 合闸速度是断路器的重要特性参数, 反映出断路器的操动机构 与传动机构在分、 合闸过程中的运动特征。 断路器分、 合闸速度超出或者低于规定值 均会影响断路器的运行状态和使用寿命。 断路器合闸速度不足, 将会引起触头合闸振 颤, 预击穿时间过长。…

互联网医院小程序源码|互联网+智慧医院解决方案

随着互联网技术的迅猛发展&#xff0c;互联网医院系统开发逐渐受到人们的关注和需求。互联网医院系统是将传统医院服务与互联网技术相结合的创新模式&#xff0c;通过互联网平台为患者提供在线诊疗、预约挂号、药品配送等医疗服务。下面就来介绍一下互联网医院系统开发的优势。…

【宝藏系列】20个常用的Python技巧

【宝藏系列】20个常用的Python技巧 文章目录 【宝藏系列】20个常用的Python技巧&#x1f349;文末推荐【Python之光】 Python的可读性和简单性是其广受欢迎的两大原因&#xff0c;本文介绍20个常用的Python技巧来提高代码的可读性&#xff0c;并能帮助你节省大量时间&#xff0…

Python实现指定区域桌面变化监控并报警

在这篇博客中&#xff0c;我们将使用Python编程语言和一些常用的库来实现一个简单的区域监控和变化报警系统。我们将使用Tkinter库创建一个图形界面&#xff0c;允许用户选择监控区域&#xff0c;并使用OpenCV库进行图像处理和相似性比较&#xff0c;以检测区域内的变化&#x…

MySQL基础扎实——MySQL数据库中的MySAM和InnDB的区别

MySAM和InnoDB是MySQL数据库中两种常见的存储引擎。 MySAM&#xff08;MyISAM&#xff09;是MySQL早期版本中默认的存储引擎&#xff0c;它采用表级锁定的机制&#xff0c;适用于读操作较多、写操作较少的场景。下面是MySAM和InnoDB的区别&#xff1a; 事务支持&#xff1a;My…

【树上乘法原理】ICPC Shanghai 2021 G, Edge Groups

http://oj.daimayuan.top/course/8/problem/400 题意&#xff1a; 思路&#xff1a; 求方案数&#xff0c;考虑组合数学 手摸一下样例发现&#xff0c;对于一棵子树&#xff0c;若边数为偶数&#xff0c;那么可以内部匹配&#xff0c;但是如果边数为奇数&#xff0c;那么就一…