C语言自定义函数可变参数问题!_百度知道
C语言自定义函数可变参数问题!
一、需要借用C语言的VA_LIST 宏定义,及相关操作来实现可变参数。VA_LIST 所在头文件:#include &stdarg.h&,用法如下:(1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针;(2)然后用VA_START宏初始化刚定义的VA_LIST变量;(3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型(如果函数有多个可变参数的,依次调用VA_ARG获取各个参数);(4)最后用VA_END宏结束可变参数的获取。二、以下是一个自定义打印接口的实现:int&my_printf(const&char&*fmt,&...)//...表示参数可变{&&&&va_list&//定义va_list&&&&&&&&static&char&gc_PrintfOutBuff[1000];&&&&va_start(args,&fmt);//初始化&&&&vsnprintf((char&*)&gc_PrintfOutBuff,&1000,&(char&*)&fmt,&args);//这里没有使用VA_ARG取回单个变量,而是借用vsnprinf一次性读取。&&&&va_end(args);//结束获取&&&&puts(&%s&,(const&char&*)gc_PrintfOutBuff);//使用。&&&&return&0;}
其他类似问题
为您推荐:
提问者采纳
va_start(arg_ptr,因此. ,如何自己实现printf函数。 ,则va_arg(argp,这里的条件就是判断参数值是否为-1,也就是说你没办法从声明中看到所接受的参数; printf(" 目前; ...因为得到参数的地址之后;只能在运行时确定参数形式& 这时候再调用va_arg(argp,函数的功能只是打印所有参数的值,-1),不过独门偏方倒是有一个;int printf( const char* int printf( const char *format [,其后占位符…,argp的类型是char *; va_list argp。因此; ,也就是可变长参数; .,需要编写一个函数,然后在函数中根据根据需要任意解释它们的含义,i),为什么;& /* 将va_list传递给子函数 */&printf(& #define va_arg(& //以固定参数的地址为起点确定变参的内存起始地址, ;the number is %d .,否则南辕北辙各说各话就惨了;; 。 。从这个函数的实现可以看到;& 有这样一个具有可变长参数的函数; typedef char* va_ ,其中有下列代码用来获取类型为float的实参; }&⑷然后依次用va_arg宏使arg_ptr返回可变参数的地址;}&C语言中有一种长度不确定的参数:& ,实际调用时可以有以下的形式:可变参数函数的使用&); ,它主要用在参数个数不确定的函数中.h&& 显然; 。& 。& ,(int (*)() *)是无意义的; //得到下一个可变参数的值 !\n& 答案与分析。这就是main函数中argv的含义。& 有时候; { .;& /* 从argp中逐一取出所要的参数 */&& 使用例; 问题!\n& int n = vprintf(&the %d th arg: ,表示后面参数的个数不定.,和一个va_list的typedef声明: :&&原则.; 目前没有&&& }& ..),在看完这几个宏的内部实现机制后,200; void subfunc (char *fmt。& ,它包含了一组宏; #define va_start(list) list = (char*)&下面解释一下这些代码; ,那就是main();& (*(int (*)() *)(((argp) += sizeof (int (*)())) -sizeof (int (*)())))& va_end(ap),但它还是不能表示任意数量的函数参数:可变长参数的传递& do ,& ,如何处理其中的可变参数问题, …)&&& ,char *argv[]),这是我当时收藏一个网友;⑶然后用va_start宏初始化⑵中定义的变量arg_ptr,后面跟的参数的个数和类型是可变的(用三个点“…”做参数占位符); (*(type *)(((argp) += sizeof(type)) - sizeof(type)))& }& 原型;第二篇 。& va_list arg_ 不可以; 问题.)& ((mode*) (list += sizeof(mode)))[-1]& ,当然: ,这个函数参数的具体形式可以在运行时才确定;&#include & , type) \ , fmt); 自己实现&& int f (,所有的输入参数必须都是整数,这里会由几个问题引发一些对它的分析。 :可变长参数中类型为函数指针& int (*)();的解决办法;& 答案与分析。& , char* argv[])& .;& 深入想一下? .; ?&va在这里是variable-argument(可变参数)的意思; int main(C语言之可变参数问题 .; . ,nArgC {& ,理所当然会有一个要求. , s);//示例代码1; 。一个典型实现如下;&& #define va_arg(void va_end( va_list arg_ptr ): %d& printf(": ,我们使用可变参数应该有以下步骤; 如果你想用va_arg从可变参数列表中提取出函数指针类型的参数; int nArgValue =start。 , float),有效性等所有方面达成一致, ;。 。也就是float类型被扩展成 //可变参数的数目& 这个与va_arg的实现有关; int nArgCout=& 。 ?& ; nArgValue = va_arg(arg_&,首先,需要用va_arg( 解决这个问题的办法是将函数指针用typedef定义成一个独立的数据类型,我们定义被调用函数的参数为va_list类型.)&& ,-1),自然就会明白; 为什么我的编译器不允许我定义如下的函数;一个简单的可变参数的C函数 :%s&&.:& :定义可变长参数的一个限制 ,形如; ,应用的是",即最后一个固定参数:& 请问; arg = va_arg (fmt: :& /* 将可变长参数转换为va_list */& 。在这个例子里;&int main(int argc:printf的实现&&printf(",解释很全面第一篇& } while(nArgV&& : ,但我们必然要在函数中解析参数的意义, int (*)())被扩展为; 这样做可以吗,int):&函数的参数是argc和argv, format),这为我们使用提供了进一步的方便; , ,再结合参数的类型.,同时在调用函数中将可变长参数列表转换为va_ } ,结合参数的类型;,你尚无办法直接做到这一点.; ,其函数原型为。对char和short类型的则用va_arg(⑸设定结束条件;& 。&&&void va_start( va_list arg_ #define va_end(list) :在C++中有函数重载(overload)可以用来区别不同函数参数的调用; 这个参数将被传递给va_start();正规&&…&&{& 先看例子程序:&&&The value is %d;,这个要求能否实现,才能得到参数的值; .; ,但是我们可以迂回前进;&这些宏定义在 问题;void simple_va_fun(int start,大小:运行时才确定的参数&C语言编程中有时会遇到一些参数个数可变的函数;& 问题,如果你要去可变长参数列表中原来为float类型的参数;& 。&type va_arg( va_list arg_ptr!= -1); ,将它的可变长参数直接传递给另外的函数;&& 。一个简单的,这样就可以进行变长参数的传递了。&加宽"。常用的办法是你可 以通过定义一个void *类型的参数; 这种可变参数可以说是C语言一个比较难理解的部分; simple_va_fun(100, short被扩展成& simple_va_fun(100,s), mode)\ , int),这里是arg_ ,程序员必须自己在代码中指明结束条件。&&Enj& 答案与分析, funcptr)将被扩展为,这个变量是存储参数地址的指针;stdarg,例如,这个参数不是必需的; 有没有办法写一个函数.; 注意。该函数至少有一个整数参数; 这样就可以通过编译检查了. ); 问题。看如下所示。在可变长参数中;& ,结果却总是不正确; 不可以。函数代码如下; 问题;0& 虽然参数没有固定形式:& ,",就是调用者和被调者之间要对参数区内容的格式,例如printf()函数? 答案与分析;⑵函数里首先定义一个va_list型的变量; .&& , type ),nArgValue); va_start( int printf(char* format, argument],然后用va_arg()和va_end()来确定所有实际调用时可变长参数的类型和值;printf(":可变长参数的获取&&#include & void mainfunc (char *& return?& ,请问。注意被调的函数在调用时是不知道可变参数的正确数目的; 。&;; subfunc (&&& typedef int (*funcptr)()., argp),得到这个地址之后;⑴由于在程序中将用到以下这些宏: :& 其中;%d": ,因为有一个函数已经给我们做出了这方面的榜样; , argp)、演示版的va_arg实现如下;&& {&& ,它的原型是; 。这是ANSI C 所要求的。至于为什么它不会知道参数的数目; ,用它来指向实际的参数区,start);}& , prev_param ):& 我想使用va_arg来提取出可变长参数中类型为函数指针的参数: ,而 printf(& ,你至少得定义一个固定参数;&& ;char,就可以得到参数的值; //输出各参数的值&它除了有一个参数format固定以外, ap);va_alist& va_start (argp: :& 答案与分析;&{& ?& 在标准C语言中定义了一个头文件专门用来对付可变参数列表; ;& va_arg (argp.h中; { ,也即是参数根本就没有固定的形式,则用来表明实际 的参数个数; ,所以用到可变参数的程序应该包含这个头文件: 。 ,例如&%s".)& 答案与分析; va_end (argp),我们最容易想到的例子是printf函数; ,这个宏的第二个参数是可变参数列表的前一个参数., ++nArgCout, va_list argp)& ;stdio,但是没有任何的固定参数, double); va_list ap.h& return 0; {& (* (funcptr *)(((argp) += sizeof (funcptr)) - sizeof (funcptr))) : , value); #include :耐心看
提问者评价
来自团队:
c语言的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁引用参数_百度百科
本词条缺少名片图,补充相关内容使词条更完整,还能快速升级,赶紧来吧!
引用参数是由调用部位传入的地址(写在留言板上)的。
引用参数简介
引用参数是由调用部位传入的地址(写在留言板上)的。
在表中以符号“&”开始的参数即为引用参数。如果一个是引用参数,调用部位将把的地址传递给。可以改变传递给引用参数的任何,因为子程序操作的是真正的,而不是它的副本。
把参数声明成引用,实际上改变了缺省的按值传递参数的传递机制,在按值传递时,函数操纵的是实参的本地拷贝。
引用参数常见用法
一、引用参数的三种常见用法:
1.需要改变实参的值,比如swap()。参数是引用时,函数接收的是实参的左值而不是值的拷贝。这意味着函数知道实参在内存中的位置,因而能够改变它的值或取它的地址。 2.向主调函数返回额外的结果。如下例:
/***Description: 测试引用传递的第二种使用方式* Author:charley* DateTime: 23:00* Compile Environment:win7 32 位 +vs2008***
/#include &iostream&
#include &vector&
// 引用参数 'occurs' 可以含有第二个返回值
vector&int&::const_iterator look_up( const vector&int& &vec, int value, /* 值在 vector 中吗?*/ int &occurs ) /* 多少次?*/
// res_iter 被初始化为最后一个元素的下一位置
vector&int&::const_iterator res_iter = vec.end();
occurs = 0;
for ( vector&int&::const_iterator iter = vec.begin(); iter != vec.end(); ++iter )
//判断是否存在value
if ( *iter == value ) { //只有第一次找到value时,该项才成立;
//找到第二个value时res_iter已经被下一步赋值了,该项不成立
//达到在多次出现value的情况下,指向第一次出现的iterator 被返回
if ( res_iter == vec.end() )
res_iter =
} //如果找不到该value值,返问一个指向vector 最后一个元素下一位置的iterator
return res_
/*** 调用look_up方法*/
int main_test6()
vector&int& vI
cout&&&请输入数字,按Ctrl+Z结束:&&&
while(cin&&iVal)
vInts.push_back(iVal);
if(vInts.size()==0){
cout&&&没有元素。&&&
return -1;
cout&&&您输入的结果如下:&&&
for(vector&int&::const_iterator iter = vInts.begin(); iter!=vInts.end();iter++)
cout&&*iter&&&\t&;
int occurs = 0; //查找该容器中是否含有值2。
vector&int&::const_iterator resIter = look_up(vInts,2,occurs);
if(!occurs)
cout&&&容器中不含2。&&&
cout&&&容器中2出现了:&&&occurs&&&次,*iterator为:&&&*resIter&&
3.向函数传递大型的类对象。例如:
class Huge {
double stuff[1000];
}; extern int calc( const Huge & ); int main() { Huge table[ 1000 ]; // ... 初始化 table int sum = 0; for ( int ix=0; ix & 1000; ++ix ) // 函数 calc() 将指向 Huge 类型的数组元素指定为实参 sum += calc( table[ix] ); // ... }
二、如果引用参数不希望在被调用的函数内部被修改,那么把参数声明为 const 型的引用是个不错的办法。
class X; extern int foo_bar( X& ); int foo( const X& xx ) { // 错误: const 传递给非 const return foo_bar( xx ); } 为使该程序通过编译 我们改变 foo_bar()的参数的类型 以下两种声明都是可以接受的 extern int foo_bar( const X& ); extern int foo_bar( X ); // 按值传递
或者可以传递一个 xx 的拷贝做实参 允许 foo_bar()改变它 int foo( const X &xx ) { // ... X x2 = // 拷贝值 // 当 foo_bar() 改变它的引用参数时, x2 被改变, xx 保持不变 return foo_bar( x2 ); // ok }
三、 我们可以声明任意内置数据类型的引用参数
例如,如果程序员想修改指针本身,而不是指针引用的对象,那么他可以声明一个参数,该参数是一个指针的引用,例如:下面是交 换两个指针的函数
void ptrswap( int *&v1, int *&v2 ) { int *tmp = v2; v2 = v1; v1 = }
如下声明 int *&v1; //实际是为指针取了一个别名,这样就可以通过别名改变指针本身 应该从右向左读,v1 是一个引用,它引用一个指针,指针指向 int 型的对象。
用函数 main() 操纵函数 rswap() 我们可以如下修改代码以便交换两个指针值:
#include &iostream& void ptrswap( int *&v1, int *&v2 ); int main() { int i = 10; int j = 20; int *pi = &i; int *pj = &j; cout && &Before ptrswap():\tpi: & && *pi && &\tpj: & && *pj && //参数为指针的别名(即指针的引用,那么传递的实参就是指针本身,道理和传递普通变量一样的) ptrswap( pi, pj ); cout && &After ptrswap():\tpi: & && *pi && &\tpj: & && *pj && return 0; }
编译并运行程序 产生下列输出 Before ptrswap(): pi: 10 pj: 20 After ptrswap(): pi: 20 pj: 10
四、引用参数还是指针参数
这2种参数都能够改变实参的值,也可以有效的传递大型类对象,怎么样决定参数该声明成哪种呢?
根本区别是:引用必须被初始化为指向一个对象,一旦初始化了,它就不能再指向其他对象;指针可以指向一系列不同的对象也可以什么都不指向 。
因为指针可能指向一个对象或没有任何对象,所以函数在确定指针实际指向一个有效的对象之前不能安全地解引用(dereference) 一个指针,例如: class X; void manip( X *px ) { // 在解引用指针之前确信它非 0 if ( px != 0 ) // 解引用指针 }
另一方面,对于引用参数,函数不需要保证它指向一个对象。引用必须指向一个对象,甚至在我们不希望这样时也是如此,例如 : class Type { }; void operate( const Type& p1, const Type& p2 ); int main() { Type obj1; // 设置 obj1 为某个值 // 错误: 引用参数的实参不能为 0 Type obj2 = operate( obj1, 0 ); }
如果一个参数可能在函数中指向不同的对象,或者这个参数可能不指向任何对象,则必须使用指针参数 。
引用参数的一个重要用法是:它允许我们在有效地实现重载操作符的同时,还能保证用法的直观性。
以Matrix 对象的加法重载操作符来举例:
Matrix // 加法返回一个 Matrix 对象 operator+( // 重载操作符的名字 Matrix m1, // 操作符左操作数的类型 Matrix m2 // 操作符右操作数的类型 ) { M // do the computation in result }
可以这样使用:
Matrix a,b,c; a = b+c; a+b+c;
但是operator+是按值传递,效率较低,如果我们改成指针参数:
Matrix operator+( Matrix *m1, Matrix *m2 )
{ M // 在 result 中计算 }
虽然在获得了效率,但在使用时将出现这样的代码:a = &b +&c 和&( &a+&b)+&c;显然并不友好。
下面是 Matrix类的重载加法操作符的修订版本 // 使用引用参数的新实现 Matrix operator+( const Matrix &m1, const Matrix &m2 ) { M // 在 result 中进行计算 } 该实现支持如下形式的 Matrix对象的加法 a + b + cC语言中形参与实参是什么?请具体解释。_百度知道
C语言中形参与实参是什么?请具体解释。
提问者采纳
形参:全称为&形式参数&是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传如的参数. 实参:全称为&实际参数&是在调用时传递个该函数的参数. 形参和实参的类型必须要一致,或穿筏扁禾壮鼓憋态铂卡者要符合隐含转换规则, 当形参和实参不是指针类型时,在该函数运行时,形参和实 参是不同的变量,他们在内存中位于不同的位置,形参将实 参的内容复制一份,在该函数运行结束的时候形参被释放, 而实参内容不会改变. 而如果函数的参数是指针类型变量,在调用该函数的过程 中,传个函数的是实参的地址,在函数体内部使用的也是 实参的地址,即使用的就是实参本身.所以在函数体内部 可以改变实参的值. 给你一个很简单的例子: int f(int b) /*b为形参*/ {} main() {int a=1; printf(&%d&,f(a));/*a为实参*/ }
提问者评价
太给力了,你的回答完美地解决了我的问题,非常感谢!
来自团队:
其他类似问题
为您推荐:
其他2条回答
形参是传递给函数的数据实参就是被传递的数据 打个比方:有个函数 fum(int a)你在主函数中定义的变量 int b那么b就是实参a就是形参 类似与你用QQ给别人传文件你的文件叫实参那个正在传输过程最终到达别人那里的文件叫形参
void func ( int a) {
// 这里你用到a,就是形参。因为a在调用func的时候才会产生,在这之前,代码里都只是参数的形式。} void main(void){
func(b);// b就是实际参数。 }
c语言的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁函数与指针_图文_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
评价文档:
函数与指针
上传于||暂无简介
大小:855.00KB
登录百度文库,专享文档复制特权,财富值每天免费拿!
你可能喜欢}