详解C语言可变参数列表(stdarg头文件及其定义的宏)

简介: 详解C语言可变参数列表(stdarg头文件及其定义的宏)

   前言:在一些函数定义时,()内的参数并不是所有的函数参数都是唯一的,如printf函数的定义

这里的省略号就代表printf函数的参数是可以变化的,而对于一些函数其参数是固定的,如strlen

之所以有这样的不同,主要还是因为函数的作用不同,printf函数需要打印多个不同类型的数据,而strlen函数是计算字符串长度,只需要传递字符串地址即可。使用可变参数列表可以很好的解决我们的需求,而可变参数列表的实现是通过头文件<stdarg>实现的,下面就来详细介绍;

2.stdarg头文件的介绍

       基本概念:定义宏,来处理未知类型,未知参数个数的函数

       使用方法:在基本参数之后添加...来代表未知的类型,未知的参数个数

va_list  的介绍

 原型:              typedef char* va_list;

   va_list是一种指向可变参数列表的指针(注意:是指向整个可变参数列表的指针,并没有指向第一个参数,指向第一个参数需要通过va_start来实现)

       va_list arg;定义了一个数据类型为va_list的变量arg,用于进行可变参数列表的操作

va_start 的介绍

       原型:           void va_start(va_list ap, last_arg);

        具体来说:va_start的参数有两个,第一个是va_list数据类型的变量(也就是一个指向可变参数列表的指针),第二个是可变参数列表前的最近的一个参数(也就是...之前的)

       作用:初始化可变参数列表,将指针指向可变参数列表的第一个参数,使程序能够一一访问可变参数列表的每一个参数:

       va_start(arg,num);num是我自己设置的函数参数(...之前的最近的一个参数)

   

va_arg 的介绍

       

       用法:获取可变参数列表的每一个参数,并将其返回,同时将指针指向下一个参数;

       va_arg(arg,double);

va_end的介绍

       

        作用:结束对可变参数列表的访问,并释放资源

2.一个简单的例子(求任意参数的平均数)

#include <stdio.h>
#include <stdarg.h>
/*函数声明部分*/
double average(int num, ...)
{
    /*定义一个可变参数列表*/
    va_list valist;
    /*初始化可变参数列表,使其指向可变参数列表的第一个参数*/
    va_start(valist, num);
    int i = 0;
    double sum = 0.0;//用于存储总和
    for (i = 0; i < num; i++)
    {
        /*访问可变参数列表的每一个值,并将其返回*/
        sum += va_arg(valist, double);
    }
    /*清理valist所占用的内存*/
    va_end(valist);
    return sum / num;
}
int main()
{
    /*存储任意参数*/
    double a = average(10, 12.0, 23.0, 34.0, 45.0, 56.0, 76.0, 32.0, 33.0, 11.0, 90.0);
    double b = average(5, 22.3, 44.2, 14.5, 66.3, 99.5);
    printf("平均值=%.2lf\n", a);
    printf("平均值=%.2lf\n", b);
    return 0;
}

总结: 利用可变参数列表的设计程序的步骤

1.编写相应的函数,在函数参数部分添加固定参数和...来表示可变参数列表;

2.定义一个va_list类型的变量,作为可变参数列表;

3.使用va_start来初始化可变参数列表,使指针指向可变参数列表的第一个参数;

4.使用va_arg不断访问可变参数列表的每一个参数,并获得其参数,同时指向下一个参数;

5.使用va_end来清理可变参数列表的内存,释放资源;

       Tip:使用时一定要注意格式,va_list后面直接跟可变参数列表的名称即可;va_start( , )第一个参数是列表名称,第二个是函数中的固定参数(比如上述代码的num);va_arg( , )第一个参数是列表名称,第二个参数是可变参数的数据类型;va_end()参数是列表名称;

目录
相关文章
|
11月前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
889 14
|
11月前
|
C语言
【C语言】全局搜索变量却找不到定义?原来是因为宏!
使用条件编译和 `extern` 来管理全局变量的定义和声明是一种有效的技术,但应谨慎使用。在可能的情况下,应该优先考虑使用局部变量、函数参数和返回值、静态变量或者更高级的封装技术(如结构体和类)来减少全局变量的使用。
200 5
|
11月前
|
C语言
【C语言】头文件命名详解 - 《铁头无敌 ! 》
头文件在C语言编程中起着组织代码和提高代码复用性的作用。标准头文件提供了丰富的库函数,而自定义头文件可以将常用函数、宏定义、类型定义等封装起来,以便在多个源文件中共享。遵循良好的头文件命名和使用约定,有助于编写清晰、易维护的C语言程序。
381 3
|
12月前
|
存储 算法 C语言
C语言中常见的字符串处理技巧,包括字符串的定义、初始化、输入输出、长度计算、比较、查找与替换、拼接、截取、转换、遍历及注意事项
本文深入探讨了C语言中常见的字符串处理技巧,包括字符串的定义、初始化、输入输出、长度计算、比较、查找与替换、拼接、截取、转换、遍历及注意事项,并通过案例分析展示了实际应用,旨在帮助读者提高编程效率和代码质量。
654 4
|
11月前
|
编译器 C语言
【C语言】宏定义在 a.c 中定义,如何在 b.c 中使用?
通过将宏定义放在头文件 `macros.h` 中,并在多个源文件中包含该头文件,我们能够在多个文件中共享宏定义。这种方法不仅提高了代码的重用性和一致性,还简化了维护和管理工作。本文通过具体示例展示了如何定义和使用宏定义,帮助读者更好地理解和应用宏定义的机制。
500 2
|
存储 编译器 C语言
C语言函数的定义与函数的声明的区别
C语言中,函数的定义包含函数的实现,即具体执行的代码块;而函数的声明仅描述函数的名称、返回类型和参数列表,用于告知编译器函数的存在,但不包含实现细节。声明通常放在头文件中,定义则在源文件中。
|
安全 编译器 C语言
C语言常量的定义与使用的注意点
在 C 语言中,常量是在程序运行期间值不变的量,通过字面值、`#define` 或 `const` 关键字定义。字面常量直接在代码中表示固定值,如整数 `100`、浮点数 `3.14`、字符 `&#39;A&#39;` 和字符串 `&quot;Hello, World!&quot;`;`#define` 用于定义宏,如 `#define PI 3.14159`;`const` 则定义不可变变量,如 `const int daysInWeek = 7`。常量可用于数组大小、循环边界等场景,并能提升代码的可读性和可维护性。使用时需注意作用域、类型安全和命名,避免直接使用数字(魔法数字)。
|
测试技术 C语言
《测试驱动的嵌入式C语言开发》——3.3节写一个测试列表
本节书摘来自华章社区《测试驱动的嵌入式C语言开发》一书中的第3章,第3.3节写一个测试列表,作者:(美)James W. Grenning,更多章节内容可以访问云栖社区“华章社区”公众号查看
1429 0
|
2月前
|
存储 C语言
`scanf`是C语言中用于按格式读取标准输入的函数
`scanf`是C语言中用于按格式读取标准输入的函数,通过格式字符串解析输入并存入指定变量。需注意输入格式严格匹配,并建议检查返回值以确保读取成功,提升程序健壮性。
928 0
|
4月前
|
安全 C语言
C语言中的字符、字符串及内存操作函数详细讲解
通过这些函数的正确使用,可以有效管理字符串和内存操作,它们是C语言编程中不可或缺的工具。
309 15