Appearance
C 标准库 - <stdarg.h>
概述
<stdarg.h> 头文件提供了处理可变参数函数的机制,允许函数接受可变数量的参数。这是实现类似 printf() 这样的函数的基础。
可变参数类型
va_list
用于保存可变参数信息的类型。
c
typedef struct {
} va_list;可变参数宏
va_start()
c
void va_start(va_list ap, last_arg);初始化可变参数列表。
c
#include <stdio.h>
#include <stdarg.h>
void print_numbers(int count, ...) {
va_list args;
va_start(args, count);
for (int i = 0; i < count; i++) {
int num = va_arg(args, int);
printf("%d ", num);
}
va_end(args);
printf("\n");
}
int main() {
print_numbers(3, 10, 20, 30);
return 0;
}va_arg()
c
type va_arg(va_list ap, type);获取下一个可变参数。
c
#include <stdio.h>
#include <stdarg.h>
double average(int count, ...) {
va_list args;
va_start(args, count);
double sum = 0.0;
for (int i = 0; i < count; i++) {
sum += va_arg(args, double);
}
va_end(args);
return sum / count;
}
int main() {
double avg = average(4, 10.5, 20.5, 30.5, 40.5);
printf("平均值: %.2f\n", avg);
return 0;
}va_end()
c
void va_end(va_list ap);清理可变参数列表。
c
#include <stdio.h>
#include <stdarg.h>
void print_strings(int count, ...) {
va_list args;
va_start(args, count);
for (int i = 0; i < count; i++) {
char* str = va_arg(args, char*);
printf("%s\n", str);
}
va_end(args);
}
int main() {
print_strings(3, "Hello", "World", "C");
return 0;
}va_copy()
c
void va_copy(va_list dest, va_list src);复制可变参数列表(C99)。
c
#include <stdio.h>
#include <stdarg.h>
void process_args(int count, ...) {
va_list args1, args2;
va_start(args1, count);
va_copy(args2, args1);
printf("第一次遍历:\n");
for (int i = 0; i < count; i++) {
int num = va_arg(args1, int);
printf(" %d\n", num);
}
printf("第二次遍历:\n");
for (int i = 0; i < count; i++) {
int num = va_arg(args2, int);
printf(" %d\n", num);
}
va_end(args1);
va_end(args2);
}
int main() {
process_args(3, 10, 20, 30);
return 0;
}实际应用示例
1. 自定义 printf
c
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
void my_printf(const char* format, ...) {
va_list args;
va_start(args, format);
while (*format != '\0') {
if (*format == '%') {
format++;
switch (*format) {
case 'd':
printf("%d", va_arg(args, int));
break;
case 'f':
printf("%f", va_arg(args, double));
break;
case 's':
printf("%s", va_arg(args, char*));
break;
case 'c':
printf("%c", va_arg(args, int));
break;
case '%':
printf("%%");
break;
default:
printf("未知格式: %c", *format);
}
} else {
putchar(*format);
}
format++;
}
va_end(args);
}
int main() {
my_printf("整数: %d\n", 42);
my_printf("浮点数: %f\n", 3.14);
my_printf("字符串: %s\n", "Hello");
my_printf("字符: %c\n", 'A');
my_printf("混合: %d %f %s %c\n", 10, 2.5, "World", 'B');
return 0;
}2. 求和函数
c
#include <stdio.h>
#include <stdarg.h>
int sum(int count, ...) {
va_list args;
va_start(args, count);
int total = 0;
for (int i = 0; i < count; i++) {
total += va_arg(args, int);
}
va_end(args);
return total;
}
int main() {
int result1 = sum(3, 10, 20, 30);
printf("sum(10, 20, 30) = %d\n", result1);
int result2 = sum(5, 1, 2, 3, 4, 5);
printf("sum(1, 2, 3, 4, 5) = %d\n", result2);
return 0;
}3. 查找最大值
c
#include <stdio.h>
#include <stdarg.h>
int max(int count, ...) {
va_list args;
va_start(args, count);
int maximum = va_arg(args, int);
for (int i = 1; i < count; i++) {
int value = va_arg(args, int);
if (value > maximum) {
maximum = value;
}
}
va_end(args);
return maximum;
}
int main() {
int result1 = max(4, 10, 20, 30, 15);
printf("max(10, 20, 30, 15) = %d\n", result1);
int result2 = max(5, 5, 2, 8, 1, 3);
printf("max(5, 2, 8, 1, 3) = %d\n", result2);
return 0;
}4. 字符串连接
c
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
char* concat(int count, ...) {
va_list args;
va_start(args, count);
int total_length = 0;
for (int i = 0; i < count; i++) {
char* str = va_arg(args, char*);
total_length += strlen(str);
}
char* result = malloc(total_length + 1);
if (result == NULL) {
va_end(args);
return NULL;
}
result[0] = '\0';
va_start(args, count);
for (int i = 0; i < count; i++) {
char* str = va_arg(args, char*);
strcat(result, str);
}
va_end(args);
return result;
}
int main() {
char* result = concat(3, "Hello", " ", "World");
printf("连接结果: %s\n", result);
free(result);
return 0;
}5. 错误日志
c
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
void log_error(const char* format, ...) {
time_t now = time(NULL);
struct tm* tm = localtime(&now);
printf("[%04d-%02d-%02d %02d:%02d:%02d] ERROR: ",
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
printf("\n");
}
int main() {
log_error("文件未找到: %s", "config.txt");
log_error("内存分配失败,需要: %d 字节", 1024);
log_error("连接超时,服务器: %s:%d", "example.com", 8080);
return 0;
}6. 数组创建
c
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
int* create_array(int count, ...) {
int* array = malloc(count * sizeof(int));
if (array == NULL) {
return NULL;
}
va_list args;
va_start(args, count);
for (int i = 0; i < count; i++) {
array[i] = va_arg(args, int);
}
va_end(args);
return array;
}
void print_array(int* array, int size) {
for (int i = 0; i < size; i++) {
printf("%d ", array[i]);
}
printf("\n");
}
int main() {
int* arr = create_array(5, 10, 20, 30, 40, 50);
if (arr != NULL) {
print_array(arr, 5);
free(arr);
}
return 0;
}7. 多类型处理
c
#include <stdio.h>
#include <stdarg.h>
typedef enum {
TYPE_INT,
TYPE_DOUBLE,
TYPE_STRING,
TYPE_CHAR
} Type;
void print_values(int count, ...) {
va_list args;
va_start(args, count);
for (int i = 0; i < count; i++) {
Type type = va_arg(args, Type);
switch (type) {
case TYPE_INT:
printf("int: %d\n", va_arg(args, int));
break;
case TYPE_DOUBLE:
printf("double: %f\n", va_arg(args, double));
break;
case TYPE_STRING:
printf("string: %s\n", va_arg(args, char*));
break;
case TYPE_CHAR:
printf("char: %c\n", va_arg(args, int));
break;
}
}
va_end(args);
}
int main() {
print_values(6,
TYPE_INT, 42,
TYPE_DOUBLE, 3.14,
TYPE_STRING, "Hello",
TYPE_CHAR, 'A',
TYPE_INT, 100,
TYPE_DOUBLE, 2.5);
return 0;
}8. 可变参数递归
c
#include <stdio.h>
#include <stdarg.h>
int recursive_sum(int count, ...) {
va_list args;
va_start(args, count);
if (count == 0) {
va_end(args);
return 0;
}
int first = va_arg(args, int);
va_list args_copy;
va_copy(args_copy, args);
int rest = recursive_sum(count - 1);
va_end(args_copy);
va_end(args);
return first + rest;
}
int main() {
int result = recursive_sum(5, 1, 2, 3, 4, 5);
printf("递归求和: %d\n", result);
return 0;
}注意事项
1. 必须有固定参数
可变参数函数必须至少有一个固定参数。
c
#include <stdio.h>
#include <stdarg.h>
void valid_function(int count, ...) {
va_list args;
va_start(args, count);
va_end(args);
}
void invalid_function(...) {
va_list args;
va_start(args, ???);
va_end(args);
}
int main() {
valid_function(3, 1, 2, 3);
return 0;
}2. 参数类型匹配
确保使用正确的类型获取参数。
c
#include <stdio.h>
#include <stdarg.h>
void print_values(int count, ...) {
va_list args;
va_start(args, count);
for (int i = 0; i < count; i++) {
int value = va_arg(args, int);
printf("%d ", value);
}
va_end(args);
printf("\n");
}
int main() {
print_values(3, 10, 20, 30);
print_values(3, 10.5, 20.5, 30.5);
return 0;
}3. 必须调用 va_end()
每次使用 va_start 后必须调用 va_end。
c
#include <stdio.h>
#include <stdarg.h>
void good_function(int count, ...) {
va_list args;
va_start(args, count);
for (int i = 0; i < count; i++) {
int value = va_arg(args, int);
printf("%d ", value);
}
va_end(args);
printf("\n");
}
void bad_function(int count, ...) {
va_list args;
va_start(args, count);
for (int i = 0; i < count; i++) {
int value = va_arg(args, int);
printf("%d ", value);
}
printf("\n");
}
int main() {
good_function(3, 10, 20, 30);
bad_function(3, 10, 20, 30);
return 0;
}4. 参数数量限制
需要一种方法确定参数的数量。
c
#include <stdio.h>
#include <stdarg.h>
void print_with_count(int count, ...) {
va_list args;
va_start(args, count);
for (int i = 0; i < count; i++) {
int value = va_arg(args, int);
printf("%d ", value);
}
va_end(args);
printf("\n");
}
void print_with_sentinel(...) {
va_list args;
va_start(args, 0);
int value;
while ((value = va_arg(args, int)) != -1) {
printf("%d ", value);
}
va_end(args);
printf("\n");
}
int main() {
print_with_count(3, 10, 20, 30);
print_with_sentinel(10, 20, 30, -1);
return 0;
}总结
<stdarg.h> 提供的可变参数机制是 C 语言中实现灵活函数的重要工具:
- 灵活性高 - 函数可以接受不同数量的参数
- 功能强大 - 可以实现类似 printf 的函数
- 应用广泛 - 用于日志、格式化输出、数据处理等
记住:
- 必须至少有一个固定参数
- 确保使用正确的类型获取参数
- 每次使用 va_start 后必须调用 va_end
- 需要一种方法确定参数的数量