C语言可变长的参数列表详解

 更新时间:2022年01月04日 16:06:00   作者:weixin_43973403  
这篇文章主要为大家介绍了C语言可变长的参数列表,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

C语言可变长的参数列表

C语言可创建接收参数个数不确定的函数。如常用的标准库函数printf就是一个接收参数个数可变的函数。函数printf至少要接收一个字符串作为它的第一个实参。但事实上,printf还能够接收任意数目的其他实参。printf的函数原型是:

int printf(const char *format, ...);

其中的省略号(…)表示这个函数可以接收可变数目的各种类型的实参。

需要注意:这个省略号必须放在形参列表的末尾。

可变参数头文件<stdarg.h>中的宏和定义,为创建一个可变长参数列表的函数提供了必须的功能。

stdarg.h可变长参数列表类型和宏:

标识符说明
va_list该类型适合于保存宏va_start、va_arg、和va_end所需的信息。为了访问到一个可变长参数列表中的参数,必须定义一个类型为va_list的对象
va_start在一个可变长参数列表中的参数被访问前,先调用这个宏。这个宏将初始化用va_list声明的对象,以供va_arg和va_end使用
va_arg这个宏展开成一个表示可变长参数列表中下一个参数的值的表达式,值的类型由宏的第二个参数决定。每次对va_arg的调用都要修改用va_list声明的对象,以使这个对象指向列表中的下一个实参
va_end当一个函数的可变长实参列表是通过宏va_start来引用时,宏va_end可用于从这样的函数中正常返回

C11增加了宏va_copy,这个宏接受两个va_list并将第二个参数复制给第一个参数。这就允许通过可变长参数列表的多次传递不用每次都从头开始。
下面演示一个接收可变个数实参的函数average。函数average的第一个实参总是待计算平均值的数据的个数。

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

double average(int i, ...) {
	double total = 0;
	va_list ap;
	va_start(ap, i);

	for (int j = 1; j <= i; ++j) {
		total += va_arg(ap, double);
	}

	va_end(ap);
	return total / i;
}

int main() {
	double w = 37.5;
	double x = 22.5;
	double y = 1.7;
	double z = 10.2;

	printf("w = %.lf\nx = %.lf\ny = %.lf\nz = %.lf\n", w, x, y, z);
	printf("w和x的平均数:%.3f\nw、x和y的平均数:%.3f\nw、x和y和z的平均数:%.3f\n", average(2, w, x), average(3, w, x, y), average(4, w, x, y, z));
}

除了宏va_copy,函数average使用了头文件<stdarg.h>中所有的定义和宏。

上面的代码中,va_list类型的对象ap被宏va_start、va_arg和va_end用来处理函数average的可变长参数列表。

函数首先调用宏va_start来初始化对象ap,为宏va_arg和va_end使用ap做准备。

宏va_start接收两个实参——对象ap和参数列表中在省略号前的最右边的标识符,在本例中是i,宏va_start在这里使用i来判断可变长实参列表从哪里开始。

然后函数average反复地将可变长参数列表中的参数加到变量total上。通过宏va_arge,参数列表中的数据不断地被提取出来加到变量total上。

宏va_arg接收两个实参——对象ap和期望在实参列表中出现的数据的类型,在本例中是double。宏va_arg返回的是实参的值。

函数average用对象ap作为一个实参来调用宏va_end以实现从函数average正常返回到函数main中。

像printf和scanf这样带可变参数列表的函数是如何知道每个va_arg宏使用的是何种类型的数据呢?

在程序指向过程中,通过扫描格式控制字符串中的格式转换说明符来确定下一个将要出来的实参是何种类型。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

相关文章

  • Qt基础开发之Qt多线程类QThread与Qt定时器类QTimer的详细方法与实例

    Qt基础开发之Qt多线程类QThread与Qt定时器类QTimer的详细方法与实例

    这篇文章主要介绍了Qt基础开发之Qt多线程类QThread与Qt定时器类QTimer的详细方法与实例,需要的朋友可以参考下
    2020-03-03
  • C语言实现二叉链表存储

    C语言实现二叉链表存储

    这篇文章主要为大家详细介绍了C语言实现二叉链表存储的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-08-08
  • 使用c++调用windows打印api进行打印的示例代码

    使用c++调用windows打印api进行打印的示例代码

    这篇文章主要介绍了使用c++调用windows打印api进行打印的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • C语言实现简单的三子棋游戏

    C语言实现简单的三子棋游戏

    这篇文章主要为大家详细介绍了C语言实现三子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-09-09
  • C语言字符串替换:字符,字符串,字符数组详解

    C语言字符串替换:字符,字符串,字符数组详解

    这篇文章主要介绍了C++字符串替换的字符,字符串,字符数组,需要考虑的情况比较全面,有不错的借鉴价值,需要的朋友可以参考下
    2021-09-09
  • C++第三方日志库log4cplus的安装与使用配置教程

    C++第三方日志库log4cplus的安装与使用配置教程

    log4cplus是C++编写的开源的日志系统,log4cplus具有线程安全、灵活、以及多粒度控制的特点,本文给大家介绍C++第三方日志库log4cplus的安装与使用教程,感兴趣的朋友一起看看吧
    2022-02-02
  • c++ For循环执行顺序流程图解

    c++ For循环执行顺序流程图解

    for 循环允许您编写一个执行特定次数的循环的重复控制结构,这里为大家分享一下具体的执行流程,需要的朋友可以参考下
    2021-10-10
  • C++实现std::set的示例项目

    C++实现std::set的示例项目

    std::set是C++标准库中的关联容器,提供有序唯一元素集合,本文就来介绍一下std::set的具体使用,具有一定的参考价值,感兴趣的可以了解一下
    2025-02-02
  • C++ STL中vector容器的使用

    C++ STL中vector容器的使用

    这篇文章主要为大家详细介绍了C++ vector容器的使用,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • socket多人聊天程序C语言版(一)

    socket多人聊天程序C语言版(一)

    这篇文章主要为大家详细介绍了socket多人聊天程序C语言版,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10

最新评论