不定參數函式設計

使用過printf()和scanf()的人一定很好奇,為什麼只要匹配足夠的參數就可以,後面的參數可以不斷的加上去,越來越多個參數,其實這就是不定參數的函式,這裡我們就來討論這個部份。

※ 不定參數宣告

在不定參數中,是需要第一個參數,而後面可以接不定個參數如f1(3, 2, 1, 2)這樣2, 1, 2算是額外的參數,所以函式的原型應該為f1(int, ...)這就是不定參數的原型。要使用不定參數的話要含入stdarg.h這個標頭檔,因為我們會用到它的巨集功能。

* void f1(int n, ....) (合法的)
* int f2(int n, const char* s, ...) (合法的)
* char f3(char c1, .... , char c2) (不合法,省略部份必需是最後面)
* double f4(...) (不合法,沒有參數)

※ 不定參數定義

在定義中我們要取得不定參數的資料,需要用到一些巨集,但是必須覺遵守以下的規定。

1. 在函式定義中建立va_list的型態變數 (va_list ap)
2. 使用巨集將參數列表的變數初始化 (va_start(ap, lim))
3. 使用巨集來存取參數列表 (va_arg(ap, int))
4. 使用巨集來進行清理動作 (va_end(ap))

假設我們定義了一個不定參數加總的函式如下。

Example:

#include

int main()
{
int a = sum(3, 3, 1, 2);
return 0;
}
double sum(int lim, ...)
{
va_list ap;
va_start(ap, lim);
double total = 0;
int i;
for (i = 0; i < lim ; ++i)
total += va_arg(ap, double);
va_end(ap);
return total;
}

lim是有多少個數量,有兩個部份要用到這個參數,第一是為了拿來初始化ap這個va_list的參數列表,第二就是用在迴圈要跑幾次才可以取完va_arg才可以參數列表的內容全部取出來。

* va_list ap建立一個參數列表變數
* va_start(ap, lim)透過lim這個參數將ap初始化
* va_arg(ap, double)將列表中的資料一次取一個出來,第二個參數是確定型別
* va_end(ap)將ap參數列表變數釋放

在來看一個比較類似scanf()的不定參數函式設計。

Example:

#include

int main()
{
int n, m, c;
getint("#d, #d, #d", &n, &m, &c);
return 0;
}
void getint(const char* argc, ...)
{
va_list ap;
int count = 0;
int i;
while (*argc)
{
if (*argc == '#')
{
++count;
}
++argc;
}
va_start(ap, argc);
for (i = 0; i < count; ++i)
{
*va_arg(ap, int*) = i+1;
}
va_end(ap);
}

這次不定的參數傳的是int*就是地址過去,所以使用va_arg()取得的時候,第二個參數要寫int*,而直接對它解參考,寫入資料就可以確實的寫入到那些不定的參數中了。

0 意見: