A structured lesson workspace with readable content, hands-on examples, and a clean path to completion.
printf takes a variable number of arguments. You can write functions that do the same. The stdarg.h header provides va_list, va_start, va_arg, and va_end. The mechanism is low-level: you walk the stack (or register save area) manually, pulling arguments one by one. There is no type safety. There is no count. You must know the types and the number from the format string, a sentinel value, or an explicit count parameter. Get it wrong and you read garbage off the stack.
#include <stdio.h>#include <stdarg.h>double sum(int count, ...) {va_list args;va_start(args, count);double total = 0.0;for (int i = 0; i < count; i++) {total += va_arg(args, double);}va_end(args);return total;}int main(void) {printf("Sum of 2: %.1f\n", sum(2, 1.5, 2.5));printf("Sum of 4: %.1f\n", sum(4, 1.0, 2.0, 3.0, 4.0));printf("Sum of 0: %.1f\n", sum(0));return 0;}
va_start initializes the walk, anchored to the last named parameter (count). va_arg pulls the next argument and advances the internal pointer. You specify the type in va_arg. If you specify the wrong type, you read the wrong number of bytes and everything after is misaligned. va_end cleans up. You must call it before the function returns.
#include <stdio.h>#include <stdarg.h>double bad_sum(int count, ...) {va_list args;va_start(args, count);double total = 0.0;for (int i = 0; i < count; i++) {total += va_arg(args, int);}va_end(args);return total;}int main(void) {printf("Wrong type: %.1f\n", bad_sum(3, 1.5, 2.5, 3.5));return 0;}
We passed doubles but read ints. The va_arg call pulled 4 bytes instead of 8, misaligning every subsequent read. The result is garbage. The compiler did not warn us. There is no way for it to know the intended types. This is why variadic functions in C are inherently unsafe. The caller and the callee must agree on types through convention, documentation, or a format string.
When passing float arguments to a variadic function, they are promoted to double. Always use va_arg(args, double), never va_arg(args, float). Similarly, char and short are promoted to int. These default argument promotions are mandated by the standard and forgetting them causes misaligned reads.
Variadic functions are powerful and dangerous. printf is the most famous example. In modern C, consider whether a fixed-parameter function, a struct, or an array would serve better. Use variadics only when the argument count is genuinely unknown at compile time. Next: pow, for exponentiation, and the floating-point edge cases it handles.
Finish the lesson once you have worked through the material. This awards ★ 30 XP.