欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言可變參數(shù)函數(shù)詳解示例

 更新時(shí)間:2013年11月14日 10:05:23   作者:  
一般我們編程的時(shí)候,函數(shù)中形式參數(shù)的數(shù)目通常是確定的,在調(diào)用時(shí)要依次給出與形式參數(shù)對(duì)應(yīng)的實(shí)際參數(shù)。但在某些情況下我們希望函數(shù)的參數(shù)個(gè)數(shù)可以根據(jù)需要確定,因此c語言引入可變參數(shù)函數(shù)。典型的可變參數(shù)函數(shù)的例子有printf()、scanf()等,下面我就開始講解

先看代碼

復(fù)制代碼 代碼如下:

printf(“hello,world!”);其參數(shù)個(gè)數(shù)為1個(gè)。
printf(“a=%d,b=%s,c=%c”,a,b,c);其參數(shù)個(gè)數(shù)為4個(gè)。

如何編寫可變參數(shù)函數(shù)呢?我們首先來看看printf函數(shù)原型是如何定義的。
在linux下,輸入man 3 printf,可以看到prinf函數(shù)原型如下:
復(fù)制代碼 代碼如下:

SYNOPSIS
#include <stdio.h>
int printf(const char *format, ...);

后面的三個(gè)點(diǎn)...表示printf參數(shù)個(gè)數(shù)是不定的.
如何實(shí)現(xiàn)可變參數(shù)函數(shù)?
2. 編寫可變函數(shù)準(zhǔn)備
為了編寫可變參數(shù)函數(shù),我們通常需要用到<stdarg.h>頭文件下定義的以下函數(shù):
復(fù)制代碼 代碼如下:

void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list src);

其中:
va_list是用于存放參數(shù)列表的數(shù)據(jù)結(jié)構(gòu)。
va_start函數(shù)根據(jù)初始化last來初始化參數(shù)列表。
va_arg函數(shù)用于從參數(shù)列表中取出一個(gè)參數(shù),參數(shù)類型由type指定。
va_copy函數(shù)用于復(fù)制參數(shù)列表。
va_end函數(shù)執(zhí)行清理參數(shù)列表的工作。
上述函數(shù)通常用宏來實(shí)現(xiàn),例如標(biāo)準(zhǔn)ANSI形式下,這些宏的定義是:
復(fù)制代碼 代碼如下:

typedef char * va_list; //字符串指針
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )

使用宏_INTSIZEOF是為了按照整數(shù)字節(jié)對(duì)齊指針,因?yàn)閏調(diào)用協(xié)議下面,參數(shù)入棧都是整數(shù)字節(jié)(指針或者值)。
函數(shù)官方說明,如果你看到英文就煩,可以自行忽略以下說明。
va_start()
       The  va_start() macro initializes ap for subsequent use by va_arg() and
       va_end(), and must be called first.
       The argument last is the name of the last argument before the  variable
       argument list, that is, the last argument of which the calling function
       knows the type.
       Because the address of this argument may  be  used  in  the  va_start()
       macro,  it should not be declared as a register variable, or as a func‐
       tion or an array type.
va_arg()
       The va_arg() macro expands to an expression that has the type and value
       of  the  next  argument in the call.  The argument ap is the va_list ap
       initialized by va_start().  Each call to va_arg() modifies ap  so  that
       the  next  call returns the next argument.  The argument type is a type
       name specified so that the type of a pointer to an object that has  the
       specified type can be obtained simply by adding a * to type.
       The  first use of the va_arg() macro after that of the va_start() macro
       returns the argument after last.   Successive  invocations  return  the
       values of the remaining arguments.
       If  there  is  no  next argument, or if type is not compatible with the
       type of the actual next argument (as promoted according to the  default
       argument promotions), random errors will occur.
       If  ap is passed to a function that uses va_arg(ap,type) then the value
       of ap is undefined after the return of that function.
va_end()
       Each invocation of va_start() must be matched by a corresponding  invo‐
       cation of va_end() in the same function.  After the call va_end(ap) the
       variable ap is undefined.  Multiple traversals of the list, each brack‐
       eted  by va_start() and va_end() are possible.  va_end() may be a macro
       or a function.
GNU給出的一個(gè)實(shí)例:
復(fù)制代碼 代碼如下:

#include <stdio.h>
#include <stdarg.h>
void
foo(char *fmt, ...)
{
  va_list ap;
  int d;
  char c, *s;
 va_start(ap, fmt);
 while (*fmt)
     switch (*fmt++) {
     case 's': /* string */
     s = va_arg(ap, char *);
         printf("string %s\n", s);
         break;
     case 'd': /* int */
         d = va_arg(ap, int);
         printf("int %d\n", d);
         break;
     case 'c': /* char */
/* need a cast here since va_arg only takes fully promoted types */
        c = (char) va_arg(ap, int);
        printf("char %c\n", c);
        break;
   }
   va_end(ap);
}

說明:
va_start(ap, fmt);用于根據(jù)fmt初始化可變參數(shù)列表。
va_arg(ap, char *);用于從參數(shù)列表中取出一個(gè)參數(shù),其中的char *用于指定所取的參數(shù)的類型為字符串。每次調(diào)用va_arg后,參數(shù)列表ap都會(huì)被更改,以使得下次調(diào)用時(shí)能得到下一個(gè)參數(shù)。
va_end(ap);用于對(duì)參數(shù)列表進(jìn)行一些清理工作。調(diào)用完va_end后,ap便不再有效。
以上程序給了我們一個(gè)實(shí)現(xiàn)printf函數(shù)的是思路,即:通過調(diào)用va_start函數(shù),來得到參數(shù)列表,然后我們一個(gè)個(gè)取出參數(shù)來進(jìn)行輸出即可。
3.實(shí)例
例如:對(duì)于printf(“a=%d,b=%s,c=%c”,a,b,c)語句;fmt的值為a=%d,b=%s,c=%c,調(diào)用va_start函數(shù)將參數(shù)a,b,c存入了ap中。注意到:fmt中的%為特殊字符,緊跟%后的參數(shù)指明了參數(shù)類型.
因此我們的簡易printf函數(shù)如下:
復(fù)制代碼 代碼如下:

#include <stdio.h>
#include <stdarg.h>
void
myprintf(char *fmt, ...)
{
  va_list ap;
  int d;
  double f;
  char c;
  char *s;
  char flag;
  va_start(ap,fmt);
  while (*fmt){
   flag=*fmt++;
   if(flag!='%'){
 putchar(flag);
 continue;
  }
  flag=*fmt++;//記得后移一位
    switch (flag)
  {
   case 's':
 s=va_arg(ap,char*);
 printf("%s",s);
 break;
   case 'd': /* int */        
 d = va_arg(ap, int);        
 printf("%d", d);        
 break;    
   case 'f': /* double*/        
 d = va_arg(ap,double);        
 printf("%d", d);        
 break;
   case 'c': /* char*/  
 c = (char)va_arg(ap,int);       
 printf("%c", c);       
 break;
   default:
 putchar(flag);
 break;
  }  
  }
  va_end(ap);
}
int main(){
  char str[10]="linuxcode";
  int i=1024;
  double f=3.1415926;
  char c='V';
  myprintf("string is:%s,int is:%d,double is:%f,char is :%c",str,i,f,c);
}

從上面我們可以知道可變參數(shù)函數(shù)的編寫,必須要傳入一個(gè)參數(shù)fmt,用來告訴我們的函數(shù)怎樣去確定參數(shù)的個(gè)數(shù)。我們的可變參數(shù)函數(shù)是通過自己解析這個(gè)參數(shù)來確定函數(shù)參數(shù)個(gè)數(shù)的。
比如,我們編寫一個(gè)求和函數(shù),其函數(shù)實(shí)現(xiàn)如下:
復(fù)制代碼 代碼如下:

int sum(int cnt,...){
    int sum=0;
int i;
    va_list ap;
    va_start(ap,cnt);
for(i=0;i<cnt;++i)
 sum+=va_arg(ap,int);
    va_end(ap);
return sum;
}

總結(jié)一下就是:通過va_start初始化參數(shù)列表(也就能得到具體的參數(shù)個(gè)數(shù)了),然后使用va_arg函數(shù)從參數(shù)列表中取出你想要的參數(shù),最后調(diào)用va_end執(zhí)行清理工作。

相關(guān)文章

  • 探討:用兩個(gè)棧實(shí)現(xiàn)一個(gè)隊(duì)列(我作為面試官的小結(jié))

    探討:用兩個(gè)棧實(shí)現(xiàn)一個(gè)隊(duì)列(我作為面試官的小結(jié))

    作為面試官的我,經(jīng)常拿這道用兩個(gè)棧實(shí)現(xiàn)一個(gè)隊(duì)列的面試題來考面試者,通過對(duì)面試者的表現(xiàn)和反應(yīng),有一些統(tǒng)計(jì)和感受,在此做個(gè)小結(jié)
    2013-05-05
  • C語言動(dòng)態(tài)內(nèi)存的分配實(shí)例詳解

    C語言動(dòng)態(tài)內(nèi)存的分配實(shí)例詳解

    動(dòng)態(tài)內(nèi)存管理同時(shí)還具有一個(gè)優(yōu)點(diǎn),當(dāng)程序在具有更多內(nèi)存的系統(tǒng)上需要處理更多數(shù)據(jù)時(shí),不需要重寫程序,下面這篇文章主要給大家介紹了關(guān)于C語言動(dòng)態(tài)內(nèi)存分配的相關(guān)資料,需要的朋友可以參考下
    2022-06-06
  • Qt項(xiàng)目打包的實(shí)現(xiàn)步驟

    Qt項(xiàng)目打包的實(shí)現(xiàn)步驟

    本文主要介紹了Qt項(xiàng)目打包的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • C語言利用面試真題理解指針的使用

    C語言利用面試真題理解指針的使用

    C語言這門課程在計(jì)算機(jī)的基礎(chǔ)教學(xué)中一直占有比較重要的地位,然而要想突破C語言的學(xué)習(xí),對(duì)指針的掌握是非常重要的,本文將具體針對(duì)指針的基礎(chǔ)做詳盡的介紹
    2022-08-08
  • 遞歸刪除二叉樹中以x為根的子樹

    遞歸刪除二叉樹中以x為根的子樹

    今天小編就為大家分享一篇關(guān)于遞歸刪除二叉樹中以x為根的子樹,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • C++ Clock類模擬實(shí)現(xiàn)鬧鐘運(yùn)行

    C++ Clock類模擬實(shí)現(xiàn)鬧鐘運(yùn)行

    這篇文章主要為大家詳細(xì)介紹了C++ Clock類模擬實(shí)現(xiàn)鬧鐘運(yùn)行,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C語言實(shí)現(xiàn)動(dòng)態(tài)版通訊錄的代碼分享

    C語言實(shí)現(xiàn)動(dòng)態(tài)版通訊錄的代碼分享

    這篇文章主要為大家詳細(xì)介紹了如何利用C語言實(shí)現(xiàn)一個(gè)簡單的動(dòng)態(tài)版通訊錄,主要運(yùn)用了結(jié)構(gòu)體,一維數(shù)組,函數(shù),分支與循環(huán)語句等等知識(shí),需要的可以參考一下
    2023-01-01
  • C語言 scanf的工作原理詳解

    C語言 scanf的工作原理詳解

    這篇文章主要為大家介紹了C語言 scanf的工作原理,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • C++類與對(duì)象的重點(diǎn)知識(shí)點(diǎn)詳細(xì)分析

    C++類與對(duì)象的重點(diǎn)知識(shí)點(diǎn)詳細(xì)分析

    類和對(duì)象是兩種以計(jì)算機(jī)為載體的計(jì)算機(jī)語言的合稱。對(duì)象是對(duì)客觀事物的抽象,類是對(duì)對(duì)象的抽象。類是一種抽象的數(shù)據(jù)類型;變量就是可以變化的量,存儲(chǔ)在內(nèi)存中—個(gè)可以擁有在某個(gè)范圍內(nèi)的可變存儲(chǔ)區(qū)域
    2023-02-02
  • VS2019配置opencv詳細(xì)圖文教程和測試代碼的實(shí)現(xiàn)

    VS2019配置opencv詳細(xì)圖文教程和測試代碼的實(shí)現(xiàn)

    這篇文章主要介紹了VS2019配置opencv詳細(xì)圖文教程和測試代碼的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04

最新評(píng)論