c
examples
examples.c🔧c
/**
* Variable Arguments (Variadic Functions) in C - Examples
*
* This file contains comprehensive examples demonstrating
* how to work with variable argument functions in C.
*
* Compilation:
* gcc -Wall -o examples examples.c
*
* For C99 features:
* gcc -std=c99 -Wall -o examples examples.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <math.h>
#include <time.h>
/* ============================================================
* EXAMPLE 1: Basic Sum Function
* ============================================================ */
/**
* Calculates the sum of a variable number of integers
* Uses count parameter to know how many arguments to process
*/
int sum_integers(int count, ...) {
va_list args;
int total = 0;
va_start(args, count);
for (int i = 0; i < count; i++) {
total += va_arg(args, int);
}
va_end(args);
return total;
}
void example1_basic_sum(void) {
printf("=== Example 1: Basic Sum Function ===\n\n");
printf("sum_integers(3, 10, 20, 30) = %d\n",
sum_integers(3, 10, 20, 30));
printf("sum_integers(5, 1, 2, 3, 4, 5) = %d\n",
sum_integers(5, 1, 2, 3, 4, 5));
printf("sum_integers(1, 100) = %d\n",
sum_integers(1, 100));
printf("sum_integers(0) = %d\n",
sum_integers(0));
printf("\n");
}
/* ============================================================
* EXAMPLE 2: Average of Doubles
* ============================================================ */
/**
* Calculates average of variable number of doubles
*/
double average_doubles(int count, ...) {
if (count <= 0) return 0.0;
va_list args;
double sum = 0.0;
va_start(args, count);
for (int i = 0; i < count; i++) {
sum += va_arg(args, double);
}
va_end(args);
return sum / count;
}
void example2_average(void) {
printf("=== Example 2: Average of Doubles ===\n\n");
printf("average_doubles(3, 10.0, 20.0, 30.0) = %.2f\n",
average_doubles(3, 10.0, 20.0, 30.0));
printf("average_doubles(4, 1.5, 2.5, 3.5, 4.5) = %.2f\n",
average_doubles(4, 1.5, 2.5, 3.5, 4.5));
printf("average_doubles(0) = %.2f\n",
average_doubles(0));
printf("\n");
}
/* ============================================================
* EXAMPLE 3: Maximum Value
* ============================================================ */
/**
* Finds maximum of variable number of integers
*/
int find_max(int count, ...) {
if (count <= 0) return 0;
va_list args;
va_start(args, count);
int max = va_arg(args, int); /* First value as initial max */
for (int i = 1; i < count; i++) {
int val = va_arg(args, int);
if (val > max) {
max = val;
}
}
va_end(args);
return max;
}
/**
* Finds minimum of variable number of integers
*/
int find_min(int count, ...) {
if (count <= 0) return 0;
va_list args;
va_start(args, count);
int min = va_arg(args, int);
for (int i = 1; i < count; i++) {
int val = va_arg(args, int);
if (val < min) {
min = val;
}
}
va_end(args);
return min;
}
void example3_min_max(void) {
printf("=== Example 3: Minimum and Maximum ===\n\n");
printf("find_max(5, 30, 10, 50, 20, 40) = %d\n",
find_max(5, 30, 10, 50, 20, 40));
printf("find_min(5, 30, 10, 50, 20, 40) = %d\n",
find_min(5, 30, 10, 50, 20, 40));
printf("find_max(3, -5, -2, -10) = %d\n",
find_max(3, -5, -2, -10));
printf("\n");
}
/* ============================================================
* EXAMPLE 4: Sentinel-Based Approach
* ============================================================ */
/**
* Sum integers until 0 is encountered (sentinel)
*/
int sum_until_zero(int first, ...) {
if (first == 0) return 0;
va_list args;
int sum = first;
int val;
va_start(args, first);
while ((val = va_arg(args, int)) != 0) {
sum += val;
}
va_end(args);
return sum;
}
/**
* Print strings until NULL is encountered
*/
void print_strings(const char *first, ...) {
if (first == NULL) return;
va_list args;
const char *str;
printf("%s", first);
va_start(args, first);
while ((str = va_arg(args, const char*)) != NULL) {
printf(" %s", str);
}
va_end(args);
printf("\n");
}
void example4_sentinel(void) {
printf("=== Example 4: Sentinel-Based Arguments ===\n\n");
printf("sum_until_zero(10, 20, 30, 0) = %d\n",
sum_until_zero(10, 20, 30, 0));
printf("sum_until_zero(5, 15, 25, 35, 0) = %d\n",
sum_until_zero(5, 15, 25, 35, 0));
printf("print_strings: ");
print_strings("Hello", "World", "from", "C!", NULL);
printf("print_strings: ");
print_strings("One", "Two", "Three", NULL);
printf("\n");
}
/* ============================================================
* EXAMPLE 5: String Concatenation
* ============================================================ */
/**
* Concatenate variable number of strings
* Returns dynamically allocated string (caller must free)
*/
char *concat_strings(const char *first, ...) {
if (first == NULL) return strdup("");
va_list args, args_copy;
/* First pass: calculate total length */
va_start(args, first);
va_copy(args_copy, args);
size_t total_len = strlen(first);
const char *str;
while ((str = va_arg(args, const char*)) != NULL) {
total_len += strlen(str);
}
va_end(args);
/* Allocate result buffer */
char *result = malloc(total_len + 1);
if (!result) {
va_end(args_copy);
return NULL;
}
/* Second pass: concatenate strings */
strcpy(result, first);
while ((str = va_arg(args_copy, const char*)) != NULL) {
strcat(result, str);
}
va_end(args_copy);
return result;
}
void example5_string_concat(void) {
printf("=== Example 5: String Concatenation ===\n\n");
char *s1 = concat_strings("Hello", " ", "World", "!", NULL);
printf("concat_strings: \"%s\"\n", s1);
free(s1);
char *s2 = concat_strings("one", "-", "two", "-", "three", NULL);
printf("concat_strings: \"%s\"\n", s2);
free(s2);
char *s3 = concat_strings("single", NULL);
printf("concat_strings: \"%s\"\n", s3);
free(s3);
printf("\n");
}
/* ============================================================
* EXAMPLE 6: Type Promotion Demonstration
* ============================================================ */
/**
* Demonstrates type promotion rules in variadic functions
*/
void show_type_promotion(int dummy, ...) {
va_list args;
va_start(args, dummy);
/* char is promoted to int */
printf(" Reading char (promoted to int): ");
int c = va_arg(args, int); /* NOT: va_arg(args, char) */
printf("'%c' (value: %d)\n", (char)c, c);
/* short is promoted to int */
printf(" Reading short (promoted to int): ");
int s = va_arg(args, int); /* NOT: va_arg(args, short) */
printf("%d\n", s);
/* float is promoted to double */
printf(" Reading float (promoted to double): ");
double f = va_arg(args, double); /* NOT: va_arg(args, float) */
printf("%.2f\n", f);
/* int stays as int */
printf(" Reading int: ");
int i = va_arg(args, int);
printf("%d\n", i);
/* double stays as double */
printf(" Reading double: ");
double d = va_arg(args, double);
printf("%.2f\n", d);
va_end(args);
}
void example6_type_promotion(void) {
printf("=== Example 6: Type Promotion ===\n\n");
printf("Calling with: 'A', (short)100, 3.14f, 42, 2.718\n");
show_type_promotion(0, 'A', (short)100, 3.14f, 42, 2.718);
printf("\n");
}
/* ============================================================
* EXAMPLE 7: va_copy Usage
* ============================================================ */
/**
* Demonstrates using va_copy to process arguments multiple times
*/
void process_twice(int count, ...) {
va_list args1, args2;
va_start(args1, count);
va_copy(args2, args1); /* Create a copy */
/* First pass: print values */
printf(" Values: ");
for (int i = 0; i < count; i++) {
printf("%d ", va_arg(args1, int));
}
printf("\n");
/* Second pass: calculate sum using the copy */
int sum = 0;
for (int i = 0; i < count; i++) {
sum += va_arg(args2, int);
}
printf(" Sum: %d\n", sum);
va_end(args1);
va_end(args2); /* Both must be ended! */
}
void example7_va_copy(void) {
printf("=== Example 7: Using va_copy ===\n\n");
printf("process_twice(4, 10, 20, 30, 40):\n");
process_twice(4, 10, 20, 30, 40);
printf("\nprocess_twice(3, 5, 15, 25):\n");
process_twice(3, 5, 15, 25);
printf("\n");
}
/* ============================================================
* EXAMPLE 8: Simple Printf Implementation
* ============================================================ */
/**
* A simplified printf implementation
*/
void my_printf(const char *format, ...) {
va_list args;
va_start(args, format);
for (const char *p = format; *p != '\0'; p++) {
if (*p != '%') {
putchar(*p);
continue;
}
p++; /* Skip '%' */
switch (*p) {
case 'd':
case 'i':
printf("%d", va_arg(args, int));
break;
case 'u':
printf("%u", va_arg(args, unsigned int));
break;
case 'f':
printf("%f", va_arg(args, double));
break;
case 's': {
char *s = va_arg(args, char*);
printf("%s", s ? s : "(null)");
break;
}
case 'c':
putchar(va_arg(args, int));
break;
case 'x':
printf("%x", va_arg(args, unsigned int));
break;
case 'X':
printf("%X", va_arg(args, unsigned int));
break;
case 'p':
printf("%p", va_arg(args, void*));
break;
case '%':
putchar('%');
break;
case '\0':
p--; /* Back up - will exit loop */
break;
default:
putchar('%');
putchar(*p);
break;
}
}
va_end(args);
}
void example8_my_printf(void) {
printf("=== Example 8: Simple Printf Implementation ===\n\n");
printf("Standard printf: ");
printf("Name: %s, Age: %d, Score: %.2f\n", "Alice", 25, 95.5);
printf("Custom my_printf: ");
my_printf("Name: %s, Age: %d, Score: %f\n", "Alice", 25, 95.5);
printf("\nMore examples:\n");
my_printf(" Char: %c, Hex: %x, Pointer: %p\n", 'X', 255, (void*)&example8_my_printf);
my_printf(" Percent: %%\n");
printf("\n");
}
/* ============================================================
* EXAMPLE 9: Using vprintf Family
* ============================================================ */
/**
* Custom logging function using vfprintf
*/
void log_message(const char *level, const char *format, ...) {
va_list args;
va_start(args, format);
/* Print timestamp */
time_t now = time(NULL);
struct tm *tm_info = localtime(&now);
char time_str[20];
strftime(time_str, sizeof(time_str), "%H:%M:%S", tm_info);
fprintf(stdout, "[%s] [%s] ", time_str, level);
vfprintf(stdout, format, args);
fprintf(stdout, "\n");
va_end(args);
}
/**
* Safe sprintf wrapper using vsnprintf
*/
int safe_sprintf(char *buffer, size_t size, const char *format, ...) {
va_list args;
va_start(args, format);
int result = vsnprintf(buffer, size, format, args);
va_end(args);
return result;
}
void example9_vprintf_family(void) {
printf("=== Example 9: Using vprintf Family ===\n\n");
/* Custom logging */
log_message("INFO", "Application started");
log_message("DEBUG", "Processing %d items", 42);
log_message("ERROR", "Failed to open file: %s", "data.txt");
printf("\n");
/* Safe sprintf */
char buffer[50];
int written = safe_sprintf(buffer, sizeof(buffer),
"Result: %d + %d = %d", 10, 20, 30);
printf("safe_sprintf wrote %d chars: \"%s\"\n", written, buffer);
/* Truncation case */
char small[10];
written = safe_sprintf(small, sizeof(small), "This is too long!");
printf("Truncated (%d would be needed): \"%s\"\n", written, small);
printf("\n");
}
/* ============================================================
* EXAMPLE 10: Type-Tagged Arguments
* ============================================================ */
typedef enum {
ARG_INT,
ARG_DOUBLE,
ARG_STRING,
ARG_END
} ArgType;
/**
* Print values with explicit type tags
*/
void print_typed(ArgType first_type, ...) {
va_list args;
va_start(args, first_type);
ArgType type = first_type;
while (type != ARG_END) {
switch (type) {
case ARG_INT:
printf("int: %d\n", va_arg(args, int));
break;
case ARG_DOUBLE:
printf("double: %.2f\n", va_arg(args, double));
break;
case ARG_STRING:
printf("string: \"%s\"\n", va_arg(args, char*));
break;
default:
break;
}
type = va_arg(args, ArgType);
}
va_end(args);
}
void example10_typed_args(void) {
printf("=== Example 10: Type-Tagged Arguments ===\n\n");
printf("Mixed types with explicit type tags:\n");
print_typed(
ARG_INT, 42,
ARG_STRING, "Hello",
ARG_DOUBLE, 3.14159,
ARG_INT, 100,
ARG_STRING, "World",
ARG_END
);
printf("\n");
}
/* ============================================================
* EXAMPLE 11: Creating Arrays
* ============================================================ */
/**
* Create an integer array from variable arguments
* Uses -1 as sentinel
*/
int *create_int_array(size_t *out_size, int first, ...) {
va_list args, args_copy;
/* Count elements */
va_start(args, first);
va_copy(args_copy, args);
size_t count = 1; /* First element */
while (va_arg(args, int) != -1) {
count++;
}
va_end(args);
/* Allocate array */
int *arr = malloc(count * sizeof(int));
if (!arr) {
va_end(args_copy);
return NULL;
}
/* Fill array */
arr[0] = first;
for (size_t i = 1; i < count; i++) {
arr[i] = va_arg(args_copy, int);
}
va_end(args_copy);
*out_size = count;
return arr;
}
void example11_create_array(void) {
printf("=== Example 11: Creating Arrays ===\n\n");
size_t size;
int *arr = create_int_array(&size, 10, 20, 30, 40, 50, -1);
if (arr) {
printf("Created array of %zu elements: ", size);
for (size_t i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
free(arr);
}
/* Another example */
arr = create_int_array(&size, 5, 15, 25, -1);
if (arr) {
printf("Another array of %zu elements: ", size);
for (size_t i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
free(arr);
}
printf("\n");
}
/* ============================================================
* EXAMPLE 12: Error Handling Function
* ============================================================ */
typedef enum {
ERR_NONE = 0,
ERR_FILE_NOT_FOUND,
ERR_PERMISSION_DENIED,
ERR_INVALID_INPUT,
ERR_OUT_OF_MEMORY
} ErrorCode;
/**
* Format and print error messages
*/
void report_error(ErrorCode code, const char *format, ...) {
const char *error_names[] = {
"None",
"File Not Found",
"Permission Denied",
"Invalid Input",
"Out of Memory"
};
fprintf(stderr, "Error [%d - %s]: ", code, error_names[code]);
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "\n");
}
void example12_error_handling(void) {
printf("=== Example 12: Error Handling ===\n\n");
report_error(ERR_FILE_NOT_FOUND, "Cannot open '%s'", "config.txt");
report_error(ERR_PERMISSION_DENIED, "Access denied for user '%s' on resource '%s'",
"guest", "/etc/passwd");
report_error(ERR_INVALID_INPUT, "Expected integer, got '%s'", "abc");
report_error(ERR_OUT_OF_MEMORY, "Failed to allocate %zu bytes", (size_t)1024);
printf("\n");
}
/* ============================================================
* EXAMPLE 13: Builder Pattern
* ============================================================ */
typedef struct {
char *name;
int age;
char *email;
char *city;
} Person;
typedef enum {
FIELD_NAME,
FIELD_AGE,
FIELD_EMAIL,
FIELD_CITY,
FIELD_END
} PersonField;
/**
* Build a Person struct using variable arguments
*/
Person *build_person(PersonField first_field, ...) {
Person *p = calloc(1, sizeof(Person));
if (!p) return NULL;
va_list args;
va_start(args, first_field);
PersonField field = first_field;
while (field != FIELD_END) {
switch (field) {
case FIELD_NAME: {
const char *name = va_arg(args, const char*);
p->name = strdup(name);
break;
}
case FIELD_AGE:
p->age = va_arg(args, int);
break;
case FIELD_EMAIL: {
const char *email = va_arg(args, const char*);
p->email = strdup(email);
break;
}
case FIELD_CITY: {
const char *city = va_arg(args, const char*);
p->city = strdup(city);
break;
}
default:
break;
}
field = va_arg(args, PersonField);
}
va_end(args);
return p;
}
void free_person(Person *p) {
if (p) {
free(p->name);
free(p->email);
free(p->city);
free(p);
}
}
void example13_builder_pattern(void) {
printf("=== Example 13: Builder Pattern ===\n\n");
Person *p1 = build_person(
FIELD_NAME, "Alice",
FIELD_AGE, 30,
FIELD_EMAIL, "alice@example.com",
FIELD_CITY, "New York",
FIELD_END
);
if (p1) {
printf("Person 1:\n");
printf(" Name: %s\n", p1->name ? p1->name : "(none)");
printf(" Age: %d\n", p1->age);
printf(" Email: %s\n", p1->email ? p1->email : "(none)");
printf(" City: %s\n", p1->city ? p1->city : "(none)");
free_person(p1);
}
/* Partial build */
Person *p2 = build_person(
FIELD_NAME, "Bob",
FIELD_AGE, 25,
FIELD_END
);
if (p2) {
printf("\nPerson 2 (partial):\n");
printf(" Name: %s\n", p2->name ? p2->name : "(none)");
printf(" Age: %d\n", p2->age);
printf(" Email: %s\n", p2->email ? p2->email : "(none)");
printf(" City: %s\n", p2->city ? p2->city : "(none)");
free_person(p2);
}
printf("\n");
}
/* ============================================================
* EXAMPLE 14: Statistical Functions
* ============================================================ */
typedef struct {
double min;
double max;
double sum;
double mean;
double variance;
int count;
} Stats;
/**
* Calculate statistics for variable number of values
*/
Stats calculate_stats(int count, ...) {
Stats s = {0};
if (count <= 0) return s;
va_list args, args_copy;
va_start(args, count);
va_copy(args_copy, args);
/* First pass: min, max, sum */
s.min = s.max = va_arg(args, double);
s.sum = s.min;
for (int i = 1; i < count; i++) {
double val = va_arg(args, double);
s.sum += val;
if (val < s.min) s.min = val;
if (val > s.max) s.max = val;
}
va_end(args);
s.count = count;
s.mean = s.sum / count;
/* Second pass: variance */
s.variance = 0;
for (int i = 0; i < count; i++) {
double val = va_arg(args_copy, double);
double diff = val - s.mean;
s.variance += diff * diff;
}
s.variance /= count;
va_end(args_copy);
return s;
}
void example14_statistics(void) {
printf("=== Example 14: Statistical Functions ===\n\n");
Stats s = calculate_stats(5, 10.0, 20.0, 30.0, 40.0, 50.0);
printf("Statistics for [10, 20, 30, 40, 50]:\n");
printf(" Count: %d\n", s.count);
printf(" Sum: %.2f\n", s.sum);
printf(" Mean: %.2f\n", s.mean);
printf(" Min: %.2f\n", s.min);
printf(" Max: %.2f\n", s.max);
printf(" Variance: %.2f\n", s.variance);
printf(" Std Dev: %.2f\n", sqrt(s.variance));
printf("\n");
}
/* ============================================================
* EXAMPLE 15: Menu System
* ============================================================ */
typedef void (*MenuCallback)(void);
typedef struct {
const char *label;
MenuCallback callback;
} MenuItem;
/**
* Create and run a menu from variable arguments
*/
void run_menu(const char *title, int item_count, ...) {
MenuItem items[20];
va_list args;
va_start(args, item_count);
for (int i = 0; i < item_count && i < 20; i++) {
items[i].label = va_arg(args, const char*);
items[i].callback = va_arg(args, MenuCallback);
}
va_end(args);
printf("\n=== %s ===\n", title);
for (int i = 0; i < item_count; i++) {
printf(" %d. %s\n", i + 1, items[i].label);
}
printf(" 0. Cancel\n");
printf("\nSelect an option (0-%d): ", item_count);
int choice;
if (scanf("%d", &choice) == 1) {
if (choice > 0 && choice <= item_count) {
printf("\nExecuting: %s\n", items[choice - 1].label);
if (items[choice - 1].callback) {
items[choice - 1].callback();
}
} else if (choice == 0) {
printf("\nCancelled.\n");
}
}
}
void action_save(void) { printf(" -> Saving...\n"); }
void action_load(void) { printf(" -> Loading...\n"); }
void action_quit(void) { printf(" -> Quitting...\n"); }
void example15_menu_system(void) {
printf("=== Example 15: Menu System ===\n\n");
printf("(Demonstrating menu creation with variadic function)\n");
/* Just show structure, don't actually run interactive menu */
printf("\nSample menu structure:\n");
printf(" 1. Save Game\n");
printf(" 2. Load Game\n");
printf(" 3. Quit\n");
printf(" 0. Cancel\n");
printf("\n(Interactive menu skipped in example mode)\n");
printf("\n");
}
/* ============================================================
* MAIN - Run Selected Example
* ============================================================ */
void print_menu_list(void) {
printf("Variable Arguments (Variadic Functions) Examples\n");
printf("=================================================\n\n");
printf("Select an example to run:\n\n");
printf(" 1. Basic Sum Function\n");
printf(" 2. Average of Doubles\n");
printf(" 3. Minimum and Maximum\n");
printf(" 4. Sentinel-Based Arguments\n");
printf(" 5. String Concatenation\n");
printf(" 6. Type Promotion\n");
printf(" 7. Using va_copy\n");
printf(" 8. Simple Printf Implementation\n");
printf(" 9. Using vprintf Family\n");
printf(" 10. Type-Tagged Arguments\n");
printf(" 11. Creating Arrays\n");
printf(" 12. Error Handling\n");
printf(" 13. Builder Pattern\n");
printf(" 14. Statistical Functions\n");
printf(" 15. Menu System\n");
printf(" 0. Run all examples\n");
printf("\n");
}
int main(int argc, char *argv[]) {
int choice = -1;
if (argc < 2) {
print_menu_list();
printf("Enter example number: ");
if (scanf("%d", &choice) != 1) {
printf("Invalid input\n");
return 1;
}
printf("\n");
} else {
choice = atoi(argv[1]);
}
switch (choice) {
case 0:
example1_basic_sum();
example2_average();
example3_min_max();
example4_sentinel();
example5_string_concat();
example6_type_promotion();
example7_va_copy();
example8_my_printf();
example9_vprintf_family();
example10_typed_args();
example11_create_array();
example12_error_handling();
example13_builder_pattern();
example14_statistics();
example15_menu_system();
break;
case 1: example1_basic_sum(); break;
case 2: example2_average(); break;
case 3: example3_min_max(); break;
case 4: example4_sentinel(); break;
case 5: example5_string_concat(); break;
case 6: example6_type_promotion(); break;
case 7: example7_va_copy(); break;
case 8: example8_my_printf(); break;
case 9: example9_vprintf_family(); break;
case 10: example10_typed_args(); break;
case 11: example11_create_array(); break;
case 12: example12_error_handling(); break;
case 13: example13_builder_pattern(); break;
case 14: example14_statistics(); break;
case 15: example15_menu_system(); break;
default:
printf("Invalid choice. Run without arguments to see menu.\n");
return 1;
}
return 0;
}