本文主要介绍C语言中可变参函数的相关内容,以及展示几个简单的可变参函数功能的示例。

1. 可变参函数的概念

在使用C语言编程的时候,函数中形式参数的数目通常是确定的,在调用时要依次给出与形式参数对应的所有实际参数,但在某些情况下,我们希望函数的参数个数可以根据需要来确定(例如常见的printf()函数,它的函数参数个数就是不确定的),这时我们就需要可变参函数了。

采用 ANSI 标准形式时,可变参函数的原型声明如下:

type funcname(type para1, type para2, ...)

上述函数定义形式至少需要一个普通的形式参数,后面的省略是函数原型的一部分,表示该函数为可变参函数,type是函数返回值和形参的类型。

注意:函数参数表中的三个圆点只能放在参数表最后,即在所有普通参数之后。

2. 用法

为了能在可变参函数里取得并处理不定个数的“其他参数”,需要使用头文件<stdarg.h>提供的一套机制。

头文件<stdarg.h>提供了一个特殊类型va_list,在每个可变参函数的函数体里必须定义一个va_list类型的局部变量,它将成为访问由三个圆点所代表的实际参数的媒介。

下面假设某个可变参函数里所用的va_list类型的变量的名字是vap,我们使用vap访问实参的步骤大致如下:

1)在使用vap访问实际参数之前,必须先用宏va_start对这个变量初始化,如下:

va_start(vap, nNum);

nNum是可变参函数的最后一个确定的参数,va_start使vap指向第一个可选参数。

2)然后使用va_arg宏返回参数列表中的当前参数,并使vap指向参数列表中的下一个参数,如下:

va_arg(vap, int);

在调用宏va_arg时必须提供有关实参的实际类型(如本例中的int),这一类型也将成为这个宏调用的返回值类型。

3)在使用va_arg宏获取了所有的实参之后,最后使用va_end宏把vap指针清为NULL,如下:

va_end(vap);

我们在函数体内可以多次遍历这些由vap代表的实参,但是都必须以va_start开始,并以va_end结尾。

3. demo演示

3.1 demo1

需求:我们想定义一个函数sum,该函数可以有任意多个整型参数,函数sum最终返回这些参数的和。

我们应该将sum函数定义为一个只有一个普通参数、并具有可变长度参数表的函数,这个函数的头部应该是(函数原型与此类似):

int sum(int n, ...)

实际上我们要求在调用该函数时,第一个参数n代表想要求和的参数个数,而其余的参数为将要进行求和的参数。

完整代码(variable_arg.c)如下:

#include <stdio.h>
#include <stdarg.h>int sum(int nNum, ...)
{va_list vap;int nSum = 0;int i;va_start(vap, nNum);for (i = 0; i < nNum; i++){nSum += va_arg(vap, int);}va_end(vap);return nSum;
}int main()
{int nSumValue = 0;nSumValue = sum(3, 10, 11, 19);printf("nSumValue is: %d\n", nSumValue);return 0;
}

编译后,运行该程序,运行结果如下:

上述结果显示可变参函数sum满足了我们的需求。

3.2 demo2

需求:使用可变参函数,将可变个数的字符串参数打印出来。

我们应该将demo函数定义为一个只有一个普通参数、并具有可变长度参数表的函数,这个函数的头部应该是(函数原型与此类似):

int demo(char* msg, ...)

我们在调用该函数时,会将除msg外的其余的参数打印出来,同时需要注意,在实际调用这个函数时,要通过一定的方法指明实际参数的个数,例如把最后一个参数置为空字符串(本例采用此种方式)或其他的方式。

完整代码(variable_arg2.c)如下:

#include <stdio.h>
#include <string.h>
#include <stdarg.h>/* 函数原型声明,至少需要一个确定的参数,注意括号内的省略号*/
int demo(char*, ...);int main()
{demo("DEMO", "This", "is", "a", "demo!", "");
}/* ANSI标准形式的声明方式,括号内的省略号表示可选参数 */
int demo(char *msg, ...)
{/* 定义保存函数参数的结构 */va_list argp;/* 记录参数个数 */int argno = 0; /* 存放取出的字符串参数*/char *para;/* argp指向传入的第一个可选参数,msg是最后一个确定的参数 */va_start(argp, msg);while (1){/* 取出当前的参数,类型为char* */para = va_arg(argp, char*);/* 采用空串指示参数输入结束 */if (strcmp("", para) == 0){break;}printf("Parameter #%d is: %s\n", argno, para);argno++;}/* 将argp置为NULL */va_end(argp); return 0;
}

编译后,运行该程序,运行结果如下:

上述结果显示可变参函数demo满足了我们的需求。

C语言中可变参函数介绍与示例相关推荐

  1. go语言字符串换行_Go语言中的字符串处理方法示例详解

    1 概述 字符串,string,一串固定长度的字符连接起来的字符集合.Go语言的字符串是使用UTF-8编码的.UTF-8是Unicode的实现方式之一. Go语言原生支持字符串.使用双引号(" ...

  2. c语言字符串加减_C语言中指针的介绍

    C语言中指针的介绍 指针是C语言中广泛使用的一种数据类型. 运用指针编程是C语言最主要的风格之一.利用指针变量可以表示各种数据结构:能很方便地使用数组和字符串: 并能象汇编语言一样处理内存地址,从而编 ...

  3. C++语言类和对象介绍和示例

    C++ 类和对象 C语言中结构体(struct)是一种构造类型,可以包含若干成员变量,可以通过结构体来定义结构体变量. C++中的类(class)可以看成结构体的升级版,类也是一种构造类型,但是进行了 ...

  4. 【Android NDK 开发】Kotlin 语言中使用 NDK ( 创建支持 Kotlin 的 NDK 项目 | Kotlin 语言中使用 NDK 要点 | 代码示例 )

    文章目录 一.创建支持 Kotlin 的 NDK 项目 二.Kotlin 语言中使用 NDK 要点 1.加载动态库 2.声明 ndk 方法 3.Project 下的 build.gradle 配置 4 ...

  5. c语言中函数的介绍(血书20000字!!!!)

    文章目录 函数 一:函数是什么? 二:C语言中函数的分类 1:库函数 (1):库函数存在的意义: (2):库函数的学习与使用 2:自定义函数 (1):自定义函数的组成 (2):例题 例题一:写一个函数 ...

  6. C++语言类的多态介绍和示例

    多态按字面的意思就是多种形态.当类之间存在层次结构,并且类之间是通过继承关联时,就可能会用到多态. C++ 多态就是当调用成员函数时,会根据调用函数的对象的类型来执行不同的函数.        示例( ...

  7. C++语言动态内存管理介绍和示例

    C++动态内存 在C++程序中,所有内存需求都是在程序执行之前通过定义所需的变量来确定的. 但是可能存在程序的内存需求只能在运行时确定的情况.在这些情况下,程序需要动态分配内存,C ++语言将运算符n ...

  8. C语言中指针的介绍(终极版!!!)

    文章目录 指针 一:指针是什么? 1:内存 2:地址的生成 3:数据的储存 4:指针变量 (1):指针变量的大小 (2):如何一口气定义好几个指针变量? 二:指针与指针类型 1:指针+-整数 2.指针 ...

  9. c语言的时间函数的介绍,c语言中时间函数介绍

    asctime(将时间和日期以字符串格式表示) 相关函数:time,ctime,gmtime,localtime 表头文件:#include 定义函数:char * asctime(const str ...

  10. C语言中转义字符的介绍与使用

    1.转义字符的概念 字符集(Character Set)为每个字符分配了唯一的编号,我们不妨将它称为编码值.在C语言中,一个字符除了可以用它的实体(也就是真正的字符)表示,还可以用编码值表示.这种使用 ...

最新文章

  1. angularJS新增 品优购新增品牌
  2. go语言 rlock() defer runlock()_Go并发编程之美-读写锁
  3. Android核心分析之二十二Android应用框架之Activity
  4. 用VC6.0遇到的一个问题
  5. Android代码实现新建文件夹,并将文件保存到新建的文件夹中
  6. 通过FM CO_VB_ORDER_POST更新生产订单的Components数据
  7. 实现哈希表 java,如何实现Java的哈希表?
  8. Ubuntu下添加开机启动脚本
  9. spgridview的过滤功能回调时发生错误~
  10. css3新增了哪三种边框效果,怎么在CSS3中实现一个边框效果
  11. JDK帮助文档无法打开的常见问题和解决办法
  12. 数字信号处理常见知识点汇总
  13. netty权威指南 微云_Netty权威指南 第2版.pdf
  14. 医疗行业能否成功入场直播带货?
  15. 老树发新芽—使用 mobx 加速你的 AngularJS 应用 1
  16. oralce_函数使用
  17. docker框架及模块介绍
  18. Shark007 Advanced Codecs 11.8.5版本更新
  19. 搭建gloo网关(基于envoy)的wasm实验环境(阿里云、本机)
  20. 微信小程序仿摩拜单车

热门文章

  1. [Contest20180116]随机游走
  2. 怎么checkout一个gerrit提交,完事之后再push
  3. Hbase单机安装及使用hbase shell进行简单操作
  4. java 中的随机数
  5. java线程wait和notify详解
  6. JavaScript计时
  7. Telnet基本概念及C# Telnet 客户端程序
  8. Spark on YARN的部署
  9. 【入门一】一些简单的C程序及VS2015/Code:Blocks的使用
  10. Java的多线程机制系列:(四)不得不提的volatile及指令重排序(happen-before)