可变参数函数(二)

函数样例:

#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h>double add(int n,...)
{int i = 0;double sum = 0;va_list argptr;va_start(argptr,n);for(i = 0 ; i < n; i++){double d =  va_arg(argptr,double);printf("%d argument is %.3f\n",i,d);  //获取第i个double型的可变参数sum += va_arg(argptr,double);        }va_end(argptr);    return sum;
}int main(int argc,char **argv)
{double sum = 0;float *p = malloc(argc * sizeof(float));int i;for(i = 1; i < argc; i++)        {        p[i] = atof(argv[i]);    //printf("p[%d] = %.3f\n",i,p[i]);
    }sum = add(1,p[1]);    printf("sum = %.3f\n",sum);sum = add(2,p[1],p[2]);    printf("sum = %.3f\n",sum);sum = add(3,p[1],p[2],p[3]);    printf("sum = %.3f\n",sum);free(p);return 0;
}

运行结果:

exbot@ubuntu:~/wangqinghe/DeBug/20190702$ gcc sum.c -o sum

exbot@ubuntu:~/wangqinghe/DeBug/20190702$ ./sum 10 20 30

0 argument is 10.000

sum = 0.000

0 argument is 10.000

1 argument is 0.000

sum = 20.000

0 argument is 10.000

1 argument is 30.000

2 argument is 0.000

sum = 20.000

 

测试:double d =  va_arg(argptr,double);是否只提取可变参数列表中double类型的数据

#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h>double add(int n,...)
{int i = 0;double sum = 0;va_list argptr;va_start(argptr,n);for(i = 0 ; i < n; i++){double d =  va_arg(argptr,double);printf("%d argument is %.3f\n",i,d);sum += va_arg(argptr,double);        }va_end(argptr);    return sum;
}int main(int argc,char **argv)
{double sum = 0;float *p = malloc(argc * sizeof(float));int i;for(i = 1; i < argc; i++)        {    if(0 == i % 2)    {p[i] = atof(argv[i]);printf("float : p[%d] = %.3f\n",i,p[i]); }}sum = add(1,p[1]);    printf("sum = %.3f\n",sum);sum = add(2,p[1],p[2]);    printf("sum = %.3f\n",sum);sum = add(3,p[1],p[2],p[3]);    printf("sum = %.3f\n",sum);free(p);return 0;
}

运行结果:

exbot@ubuntu:~/wangqinghe/DeBug/20190702$ ./sum 10 20 30 40 50 60 70

float : p[2] = 20.000

float : p[4] = 40.000

float : p[6] = 60.000

0 argument is 0.000

sum = 0.000

0 argument is 0.000

1 argument is 0.000

sum = 20.000

0 argument is 0.000

1 argument is 0.000

2 argument is 0.000

sum = 20.000

结论:可变参数的输入类型要和使用的一致。(暂定)。


函数介绍:

va_list

这是一个适用于 va_start()、va_arg() 和 va_end() 这三个宏存储信息的类型。

一般情况下va_list所定义变量为字符指针,即typedef char *va_list

该类型的变量用于存储参数的地址。因为得到参数的地址之后,再结合参数的类型,才能得到参数的值。

 

va_start

宏原型是:

void va_start(va_list ap, last_arg)

参数:

ap是一个 va_list 类型的对象,它用来存储通过 va_arg 获取额外参数时所必需的信息。

last_arg是最后一个传递给函数的已知的固定参数。 

该宏与 va_arg 和 va_end 宏是一起使用的,且必须在使用 va_arg 和 va_end 之前被调用。

 

va_arg

宏原型是:

type va_arg(va_list ap, type) 

其作用是从ap开始取一个type型的值返回,并且自动将ap指向下一个参数。所以如果参数类型写错了,例如将char*写成char了,本来要取4个字节,结果只取了一个字节,ap本来要向后面移动4个字节,结果只移动了一个字节,后面的数据就全错了。

参数:

ap是一个 va_list 类型的对象,存储了有关额外参数和检索状态的信息。该对象应在第一次调用 va_arg 之前通过调用 va_start 进行初始化。

type这是一个类型名称。该类型名称是作为扩展自该宏的表达式的类型来使用的。 

返回值:该宏返回下一个额外的参数,是一个类型为 type 的表达式。

 

注意:

va_arg宏的第2个参数不能被指定为char、short或者float类型。

因为char和short类型的参数会被转换为int类型,而float类型的参数会被转换为double类型。如果错误的指定了,将会在程序中引起麻烦。

例如,这样写肯定是不对的:

c = va_arg(ap,char);

因为我们无法传递一个char类型参数,如果传递了,它将会被自动转化为int类型。上面的式子应该写成:

c = va_arg(ap,int);

va_end

宏原型为:

 void va_end(va_list ap) 

参数:

ap是之前由同一函数中的 va_start 初始化的 va_list 对象。 

其作用是作用是将ap设置为NULL,如果在从函数返回之前没有调用 va_end,则结果为未定义。

 

总结

使用可变长参数的步骤:

 

1.声明va_list变量;

2.使用va_start指定可变长参数的位置;

3.使用va_arg来获取参数值;

4.可选,使用va_end将va_list清零。

 

参考原文:https://blog.csdn.net/hmxz2nn/article/details/80445770

 

转载于:https://www.cnblogs.com/wanghao-boke/p/11121054.html

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

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

相关文章

Linux 内核网络协议栈 ------sk_buff 结构体 以及 完全解释 (2.6.16)

在2.6.24之后这个结构体有了较大的变化&#xff0c;此处先说一说2.6.16版本的sk_buff&#xff0c;以及解释一些问题。一、先直观的看一下这个结构体~~~~~~~~~~~~~~~~~~~~~~在下面解释每个字段的意义~~~~~~~~~~~[cpp] view plaincopyprint?struct sk_buff { /* These…

可变参数输出(三)

Linux C关于输出函数的定义&#xff1a; int printf(const char *format,…); int vprintf(const char * format,va_list ap); int vfprintf(FILE *stream,cosnt char *format,va_list ap); int vsprintf(char *str,const char *format,va_list ap); int vsnprintf(char *str,s…

最常用的设计模式---适配器模式(C++实现)

适配器模式属于结构型的设计模式&#xff0c;它是结构型设计模式之首&#xff08;用的最多的结构型设计模式&#xff09;。 适配器设计模式也并不复杂&#xff0c;适配器它是主要作用是将一个类的接口转换成客户希望的另外一个接口这样使得原本由于接口不兼容而不能一起工作的那…

Linux 简单打印日志(二)

#include<stdio.h> #include<stdlib.h> #include<string.h> #include<time.h> //#include<windows.h> #include <unistd.h> // linux下头文件#define FILE_MAX_SIZE (1024*1024)void get_local_time(char* buffer){time_t rawtime;struct …

程序随笔——C++实现的一个线程池

1.线程池简介 我们知道在线程池是一种多线程处理形式&#xff0c;处理过程中我们将相应的任务提交给线程池&#xff0c;线程池会分配对应的工作线程执行任务或存放在任务队列中&#xff0c;等待执行。 面向对象编程中&#xff0c;创建和销毁对象是需要消耗一定时间的&#xff0…

线程池原理及创建并C++实现

本文给出了一个通用的线程池框架&#xff0c;该框架将与线程执行相关的任务进行了高层次的抽象&#xff0c;使之与具体的执行任务无关。另外该线程池具有动态伸缩性&#xff0c;它能根据执行任务的轻重自动调整线程池中线程的数量。文章的最后&#xff0c;我们给出一个简单示例…

Linux 打印简单日志(一)

简单日志输出&#xff1a; #include<stdio.h> #include<string.h> #include<stdlib.h>void write(char* filename,char* szStr){FILE* fp;fp fopen(filename,"at");if(fp ! NULL){fwrite(szStr,256,1,fp); //fclose(fp);fp NULL;} }int main(int…

c++简单线程池实现

线程池&#xff0c;简单来说就是有一堆已经创建好的线程&#xff08;最大数目一定&#xff09;&#xff0c;初始时他们都处于空闲状态&#xff0c;当有新的任务进来&#xff0c;从线程池中取出一个空闲的线程处理任务&#xff0c;然后当任务处理完成之后&#xff0c;该线程被重…

Linux 打印可变参数日志

实现了传输进去的字符串所在的文档&#xff0c;函数和行数显示功能。 实现了将传入的可变参数打印到日志功能。 #include<stdio.h> #include<stdarg.h> #include<string.h>const char * g_path "/home/exbot/wangqinghe/log.txt"; #define LOG(fm…

C++强化之路之线程池开发整体框架(二)

一.线程池开发框架 我所开发的线程池由以下几部分组成&#xff1a; 1.工作中的线程。也就是线程池中的线程&#xff0c;主要是执行分发来的task。 2.管理线程池的监督线程。这个线程的创建独立于线程池的创建&#xff0c;按照既定的管理方法进行管理线程池中的所有线程&#xf…

vfprintf()函数

函数声明&#xff1a;int vfprintf(FILE *stream, const char *format, va_list arg) 函数参数&#xff1a; stream—这是指向了FILE对象的指针&#xff0c;该FILE对象标识了流。 format—c语言字符串&#xff0c;包含了要被写入到流stream中的文本。它可以包含嵌入的format标签…

Makefile(二)

将生产的.o文件放进指定的文件中&#xff08;先创建该文件夹&#xff09; src $(wildcard ./*.cpp) obj $(patsubst %.cpp,./output/%.o,$(src))target test$(target) : $(obj)g $(obj) -o $(target) %.o: %.cppg -c $< -o output/$.PHONY:clean clean:rm -f $(target) $…

TCP粘包问题分析和解决(全)

TCP通信粘包问题分析和解决&#xff08;全&#xff09;在socket网络程序中&#xff0c;TCP和UDP分别是面向连接和非面向连接的。因此TCP的socket编程&#xff0c;收发两端&#xff08;客户端和服务器端&#xff09;都要有成对的socket&#xff0c;因此&#xff0c;发送端为了将…

UML类图符号 各种关系说明以及举例

UML中描述对象和类之间相互关系的方式包括&#xff1a;依赖&#xff0c;关联&#xff0c;聚合&#xff0c;组合&#xff0c;泛化&#xff0c;实现等。表示关系的强弱&#xff1a;组合>聚合>关联>依赖 相互间关系 聚合是表明对象之间的整体与部分关系的关联&#xff0c…

寻找数组中第二大数

设置两个数值来表示最大数和第二大数&#xff0c;在循环比较赋值即可 //找给定数组中第二大的数int get_smax(int *arr,int length) {int max;int smax;if(arr[0] > arr[1]){max arr[0];smax arr[1];}else{max arr[1];smax arr[0];}for(int i 2; i < length; i){if(…

timerfd API使用总结

timerfd 介绍 timerfd 是在Linux内核2.6.25版本中添加的接口&#xff0c;其是Linux为用户提供的一个定时器接口。这个接口基于文件描述符&#xff0c;所以可以被用于select/poll/epoll的场景。当使用timerfd API创建多个定时器任务并置于poll中进行事件监听&#xff0c;当没有可…

#if/#else/#endif

在linux环境下写c代码时会尝试各种方法或调整路径&#xff0c;需要用到#if #include<stdio.h>int main(){int i; #if 0i 1; #elsei 2; #endifprintf("i %d",i);return 0; } 有时候会调整代码&#xff0c;但是又不是最终版本的更换某些值&#xff0c;就需要注…

内存分配调用

通过函数给实参分配内存&#xff0c;可以通过二级指针实现 #include<stdio.h> #incldue<stdlib.h>void getheap(int *p) //错误的模型 {p malloc(100); }void getheap(int **p) //正确的模型 {*p malloc(100); } int main() {int *p NULL;getheap(&p);free(p…

ESP传输模式拆解包流程

一、 ESP简介ESP&#xff0c;封装安全载荷协议(Encapsulating SecurityPayloads)&#xff0c;是一种Ipsec协议&#xff0c;用于对IP协议在传输过程中进行数据完整性度量、来源认证、加密以及防回放攻击。可以单独使用&#xff0c;也可以和AH一起使用。在ESP头部之前的IPV4…

结构体成员内存对齐

#include<stdio.h> struct A {int A; };int main() {struct A a;printf("%d\n",sizeof(a));return 0; } 运行结果&#xff1a;4 #include<stdio.h> struct A {int a;int b&#xff1b; };int main() {struct A a;printf("%d\n",sizeof(a))…