編寫函數 `float avg(int n, ...)` 接收不定數量整數參數,返回平均值。主函數調用 `avg(5, 1, 2, 3, 4, 5)` 輸出 `3.000000`。
#include
#include
float avg(int n, ...) {
va_list ap;
va_start(ap, n); // 初始化,n 為最後一個固定參數
int sum = 0;
for (int i = 0; i < n; i++) {
int val = va_arg(ap, int); // 依次提取 int 參數
sum += val;
}
va_end(ap); // 清理
return (float)sum / n;
}
int main() {
float result = avg(5, 1, 2, 3, 4, 5);
printf("平均值 = %.6f\n", result); // 3.000000
return 0;
}
| 宏 | 作用 | 注意事項 |
|---|---|---|
| `va_list ap` | 聲明參數列表指針 | 不透明類型,僅配合三宏使用 |
| `va_start(ap, last_fixed)` | 定位到第一個可變參數 | `last_fixed` 必須是最後一個**命名**參數 (此處為 `n`) |
| `va_arg(ap, type)` | 按 `type` 提取下一個參數,並推進指針 | **調用者必須保證類型匹配**,否則 UB (如傳 `double` 卻 `va_arg(ap, int)`) |
| `va_end(ap)` | 釋放資源 (某些平台需棧指針恢復) | **必須成對調用**,函數所有返回路徑均需執行 |
| `va_copy(dest, src)` (C99) | 複製參數列表狀態,支持二次遍歷 | 複製後需各自 `va_end` |
// GCC/Clang 格式化屬性檢查 (編譯期警告類型不匹配)
float avg_checked(int n, ...) __attribute__((format(printf, 2, 0)));
// 實際仍需 va_arg 手動提取,屬性僅檢查格式字符串場景
// C11 _Generic 實現類型多態 (示例:支持 int/double 混合)
#define AVG(...) _Generic((__VA_ARGS__), \
int: avg_int, \
double: avg_double \
)(__VA_ARGS__) // 需配合可變參數宏技巧,較複雜
// C++11 參數包模板 (類型安全、編譯期展開、零開銷)
template
double avg_cpp(Args... args) {
static_assert(sizeof...(Args) > 0, "至少一個參數");
double sum = (0.0 + ... + args); // 折疊表達式
return sum / sizeof...(Args);
}
// 調用
avg_cpp(1, 2, 3, 4, 5); // 3.0
avg_cpp(1.5, 2.5, 3.0); // 2.333...
// avg_cpp("str"); // 編譯錯誤:非算術類型