c

exercises

exercises.c🔧
/**
 * Variable Arguments (Variadic Functions) in C - Exercises
 * 
 * Practice problems for working with variadic functions.
 * 
 * Compilation:
 *   gcc -Wall -o exercises exercises.c -lm
 *   gcc -std=c99 -Wall -o exercises exercises.c -lm
 * 
 * With answers:
 *   gcc -Wall -DSHOW_ANSWERS -o exercises exercises.c -lm
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <math.h>

/* ============================================================
 * EXERCISE 1: Product of Integers
 * ============================================================
 * 
 * Write a variadic function that calculates the product of
 * a variable number of integers.
 * 
 * int product(int count, ...);
 * 
 * Example:
 *   product(3, 2, 3, 4) -> 24
 *   product(4, 1, 2, 3, 4) -> 24
 */

int product(int count, ...) {
    /* TODO: Implement product function */
    return 0;
}

void exercise1_product(void) {
    printf("Exercise 1: Product of Integers\n");
    printf("--------------------------------\n");
    
    /* TODO: Test your product function */
    printf("product(3, 2, 3, 4) = %d (expected: 24)\n", product(3, 2, 3, 4));
    printf("product(4, 1, 2, 3, 4) = %d (expected: 24)\n", product(4, 1, 2, 3, 4));
    printf("product(2, 10, 5) = %d (expected: 50)\n", product(2, 10, 5));
    printf("\n");
}

/* ============================================================
 * EXERCISE 2: String Join with Delimiter
 * ============================================================
 * 
 * Write a function that joins strings with a delimiter.
 * Use NULL to mark end of strings.
 * Return dynamically allocated string (caller frees).
 * 
 * char *join_strings(const char *delimiter, ...);
 * 
 * Example:
 *   join_strings(", ", "a", "b", "c", NULL) -> "a, b, c"
 */

char *join_strings(const char *delimiter, ...) {
    /* TODO: Implement join_strings function */
    return strdup("");
}

void exercise2_join_strings(void) {
    printf("Exercise 2: String Join with Delimiter\n");
    printf("---------------------------------------\n");
    
    char *s1 = join_strings(", ", "apple", "banana", "cherry", NULL);
    printf("join_strings(\", \", \"apple\", \"banana\", \"cherry\", NULL)\n");
    printf("  Result: \"%s\"\n", s1);
    printf("  Expected: \"apple, banana, cherry\"\n");
    free(s1);
    
    char *s2 = join_strings("-", "one", "two", "three", NULL);
    printf("join_strings(\"-\", \"one\", \"two\", \"three\", NULL)\n");
    printf("  Result: \"%s\"\n", s2);
    printf("  Expected: \"one-two-three\"\n");
    free(s2);
    
    printf("\n");
}

/* ============================================================
 * EXERCISE 3: Count Values in Range
 * ============================================================
 * 
 * Write a function that counts how many values fall within
 * a specified range [min, max] (inclusive).
 * 
 * int count_in_range(int min, int max, int count, ...);
 * 
 * Example:
 *   count_in_range(5, 15, 6, 3, 7, 12, 18, 9, 2) -> 3
 */

int count_in_range(int min, int max, int count, ...) {
    /* TODO: Implement count_in_range function */
    return 0;
}

void exercise3_count_range(void) {
    printf("Exercise 3: Count Values in Range\n");
    printf("----------------------------------\n");
    
    int c1 = count_in_range(5, 15, 6, 3, 7, 12, 18, 9, 2);
    printf("count_in_range(5, 15, 6, 3, 7, 12, 18, 9, 2) = %d (expected: 3)\n", c1);
    
    int c2 = count_in_range(0, 10, 5, 5, 10, 0, 15, 3);
    printf("count_in_range(0, 10, 5, 5, 10, 0, 15, 3) = %d (expected: 4)\n", c2);
    
    printf("\n");
}

/* ============================================================
 * EXERCISE 4: Custom Debug Logger
 * ============================================================
 * 
 * Implement a debug logging function with format string support.
 * Include timestamp and log level.
 * 
 * void debug_log(int level, const char *format, ...);
 * 
 * Level 0 = DEBUG, 1 = INFO, 2 = WARNING, 3 = ERROR
 */

void debug_log(int level, const char *format, ...) {
    /* TODO: Implement debug_log function */
    /* Use vprintf family */
}

void exercise4_debug_logger(void) {
    printf("Exercise 4: Custom Debug Logger\n");
    printf("--------------------------------\n");
    
    debug_log(0, "Initializing with value %d", 42);
    debug_log(1, "Processing %s file", "data.txt");
    debug_log(2, "Memory usage at %d%%", 85);
    debug_log(3, "Failed to connect after %d attempts", 3);
    
    printf("\n");
}

/* ============================================================
 * EXERCISE 5: Geometric Mean
 * ============================================================
 * 
 * Calculate the geometric mean of positive numbers.
 * Geometric mean = nth root of (x1 * x2 * ... * xn)
 * 
 * double geometric_mean(int count, ...);
 * 
 * Example:
 *   geometric_mean(3, 4.0, 1.0, 1.0/32.0) -> 0.5
 *   geometric_mean(2, 2.0, 8.0) -> 4.0
 */

double geometric_mean(int count, ...) {
    /* TODO: Implement geometric_mean function */
    /* Hint: Use logarithms to avoid overflow */
    return 0.0;
}

void exercise5_geometric_mean(void) {
    printf("Exercise 5: Geometric Mean\n");
    printf("---------------------------\n");
    
    double g1 = geometric_mean(2, 2.0, 8.0);
    printf("geometric_mean(2, 2.0, 8.0) = %.2f (expected: 4.00)\n", g1);
    
    double g2 = geometric_mean(3, 1.0, 3.0, 9.0);
    printf("geometric_mean(3, 1.0, 3.0, 9.0) = %.2f (expected: 3.00)\n", g2);
    
    double g3 = geometric_mean(4, 2.0, 2.0, 2.0, 2.0);
    printf("geometric_mean(4, 2.0, 2.0, 2.0, 2.0) = %.2f (expected: 2.00)\n", g3);
    
    printf("\n");
}

/* ============================================================
 * EXERCISE 6: Format Table Row
 * ============================================================
 * 
 * Create a function that formats values into a table row.
 * Use type tags to handle different data types.
 * 
 * Types: 'i' = int, 'f' = double, 's' = string
 * 
 * void print_table_row(const char *types, ...);
 * 
 * Example:
 *   print_table_row("sis", "Alice", 25, "Engineer");
 *   Output: | Alice      |         25 | Engineer   |
 */

void print_table_row(const char *types, ...) {
    /* TODO: Implement print_table_row function */
    /* Each column should be 10 characters wide */
}

void exercise6_table_row(void) {
    printf("Exercise 6: Format Table Row\n");
    printf("-----------------------------\n");
    
    print_table_row("sis", "Alice", 25, "Engineer");
    print_table_row("sis", "Bob", 30, "Designer");
    print_table_row("sfs", "Carol", 55000.50, "Manager");
    
    printf("\n");
}

/* ============================================================
 * EXERCISE 7: All True / Any True
 * ============================================================
 * 
 * Implement functions that check if all or any of the
 * integer arguments are non-zero (true).
 * 
 * int all_true(int count, ...);
 * int any_true(int count, ...);
 * 
 * Example:
 *   all_true(3, 1, 1, 1) -> 1
 *   all_true(3, 1, 0, 1) -> 0
 *   any_true(3, 0, 1, 0) -> 1
 *   any_true(3, 0, 0, 0) -> 0
 */

int all_true(int count, ...) {
    /* TODO: Implement all_true */
    return 0;
}

int any_true(int count, ...) {
    /* TODO: Implement any_true */
    return 0;
}

void exercise7_all_any_true(void) {
    printf("Exercise 7: All True / Any True\n");
    printf("--------------------------------\n");
    
    printf("all_true(3, 1, 1, 1) = %d (expected: 1)\n", all_true(3, 1, 1, 1));
    printf("all_true(3, 1, 0, 1) = %d (expected: 0)\n", all_true(3, 1, 0, 1));
    printf("any_true(3, 0, 1, 0) = %d (expected: 1)\n", any_true(3, 0, 1, 0));
    printf("any_true(3, 0, 0, 0) = %d (expected: 0)\n", any_true(3, 0, 0, 0));
    
    printf("\n");
}

/* ============================================================
 * EXERCISE 8: Weighted Average
 * ============================================================
 * 
 * Calculate weighted average. Arguments come in pairs:
 * (value, weight), (value, weight), ...
 * 
 * double weighted_average(int pair_count, ...);
 * 
 * Formula: sum(value * weight) / sum(weight)
 * 
 * Example:
 *   weighted_average(3, 90.0, 0.3, 80.0, 0.3, 70.0, 0.4) -> 79.0
 */

double weighted_average(int pair_count, ...) {
    /* TODO: Implement weighted_average */
    return 0.0;
}

void exercise8_weighted_average(void) {
    printf("Exercise 8: Weighted Average\n");
    printf("-----------------------------\n");
    
    double w1 = weighted_average(3, 90.0, 0.3, 80.0, 0.3, 70.0, 0.4);
    printf("weighted_average(3, 90.0, 0.3, 80.0, 0.3, 70.0, 0.4)\n");
    printf("  = %.2f (expected: 79.00)\n", w1);
    
    double w2 = weighted_average(2, 100.0, 1.0, 50.0, 1.0);
    printf("weighted_average(2, 100.0, 1.0, 50.0, 1.0)\n");
    printf("  = %.2f (expected: 75.00)\n", w2);
    
    printf("\n");
}

/* ============================================================
 * EXERCISE 9: Safe Array Builder
 * ============================================================
 * 
 * Build an array with bounds checking and type safety.
 * Return a struct with the array and its size.
 * 
 * Use -1 as sentinel to mark end of values.
 */

typedef struct {
    int *data;
    size_t size;
    size_t capacity;
} SafeArray;

SafeArray *safe_array_create(int first, ...) {
    /* TODO: Implement safe_array_create */
    /* Use -1 as sentinel */
    return NULL;
}

void safe_array_free(SafeArray *arr) {
    if (arr) {
        free(arr->data);
        free(arr);
    }
}

void exercise9_safe_array(void) {
    printf("Exercise 9: Safe Array Builder\n");
    printf("-------------------------------\n");
    
    SafeArray *arr = safe_array_create(10, 20, 30, 40, 50, -1);
    
    if (arr) {
        printf("Created array with %zu elements: ", arr->size);
        for (size_t i = 0; i < arr->size; i++) {
            printf("%d ", arr->data[i]);
        }
        printf("\n");
        safe_array_free(arr);
    } else {
        printf("(Array not created - implement safe_array_create)\n");
    }
    
    printf("\n");
}

/* ============================================================
 * EXERCISE 10: Printf with Validation
 * ============================================================
 * 
 * Implement a printf-like function that validates format
 * specifiers against provided arguments.
 * 
 * Return the number of characters printed, or -1 on error.
 * 
 * int safe_printf(const char *format, ...);
 * 
 * Support: %d, %f, %s, %c, %%
 */

int safe_printf(const char *format, ...) {
    /* TODO: Implement safe_printf */
    /* Count format specifiers and validate */
    return -1;
}

void exercise10_safe_printf(void) {
    printf("Exercise 10: Printf with Validation\n");
    printf("------------------------------------\n");
    
    int result;
    
    result = safe_printf("Hello %s, you are %d years old.\n", "Alice", 25);
    printf("  (returned: %d)\n", result);
    
    result = safe_printf("Value: %f, Char: %c\n", 3.14, 'X');
    printf("  (returned: %d)\n", result);
    
    result = safe_printf("Percent: %%\n");
    printf("  (returned: %d)\n", result);
    
    printf("\n");
}


/* ============================================================
 * ANSWER KEY
 * ============================================================ */

#ifdef SHOW_ANSWERS

/* Answer 1: Product of Integers */
int answer1_product(int count, ...) {
    if (count <= 0) return 0;
    
    va_list args;
    va_start(args, count);
    
    int result = 1;
    for (int i = 0; i < count; i++) {
        result *= va_arg(args, int);
    }
    
    va_end(args);
    return result;
}

/* Answer 2: String Join */
char *answer2_join_strings(const char *delimiter, ...) {
    va_list args, args_copy;
    va_start(args, delimiter);
    va_copy(args_copy, args);
    
    /* Calculate total length */
    size_t total_len = 0;
    size_t delim_len = strlen(delimiter);
    const char *str;
    int count = 0;
    
    while ((str = va_arg(args, const char*)) != NULL) {
        total_len += strlen(str);
        count++;
    }
    va_end(args);
    
    if (count == 0) {
        va_end(args_copy);
        return strdup("");
    }
    
    /* Add delimiter lengths */
    total_len += (count - 1) * delim_len;
    
    /* Allocate and build result */
    char *result = malloc(total_len + 1);
    if (!result) {
        va_end(args_copy);
        return NULL;
    }
    result[0] = '\0';
    
    int first = 1;
    while ((str = va_arg(args_copy, const char*)) != NULL) {
        if (!first) {
            strcat(result, delimiter);
        }
        strcat(result, str);
        first = 0;
    }
    va_end(args_copy);
    
    return result;
}

/* Answer 3: Count in Range */
int answer3_count_in_range(int min, int max, int count, ...) {
    va_list args;
    va_start(args, count);
    
    int result = 0;
    for (int i = 0; i < count; i++) {
        int val = va_arg(args, int);
        if (val >= min && val <= max) {
            result++;
        }
    }
    
    va_end(args);
    return result;
}

/* Answer 4: Debug Logger */
void answer4_debug_log(int level, const char *format, ...) {
    const char *level_names[] = {"DEBUG", "INFO", "WARN", "ERROR"};
    
    if (level < 0 || level > 3) level = 0;
    
    printf("[%s] ", level_names[level]);
    
    va_list args;
    va_start(args, format);
    vprintf(format, args);
    va_end(args);
    
    printf("\n");
}

/* Answer 5: Geometric Mean */
double answer5_geometric_mean(int count, ...) {
    if (count <= 0) return 0.0;
    
    va_list args;
    va_start(args, count);
    
    /* Use log to avoid overflow */
    double log_sum = 0.0;
    for (int i = 0; i < count; i++) {
        double val = va_arg(args, double);
        if (val <= 0) {
            va_end(args);
            return 0.0;  /* Geometric mean undefined for non-positive */
        }
        log_sum += log(val);
    }
    
    va_end(args);
    return exp(log_sum / count);
}

/* Answer 6: Table Row */
void answer6_print_table_row(const char *types, ...) {
    va_list args;
    va_start(args, types);
    
    printf("|");
    for (const char *t = types; *t; t++) {
        switch (*t) {
            case 'i':
                printf(" %10d |", va_arg(args, int));
                break;
            case 'f':
                printf(" %10.2f |", va_arg(args, double));
                break;
            case 's':
                printf(" %-10s |", va_arg(args, char*));
                break;
        }
    }
    printf("\n");
    
    va_end(args);
}

/* Answer 7: All True / Any True */
int answer7_all_true(int count, ...) {
    va_list args;
    va_start(args, count);
    
    for (int i = 0; i < count; i++) {
        if (va_arg(args, int) == 0) {
            va_end(args);
            return 0;
        }
    }
    
    va_end(args);
    return 1;
}

int answer7_any_true(int count, ...) {
    va_list args;
    va_start(args, count);
    
    for (int i = 0; i < count; i++) {
        if (va_arg(args, int) != 0) {
            va_end(args);
            return 1;
        }
    }
    
    va_end(args);
    return 0;
}

/* Answer 8: Weighted Average */
double answer8_weighted_average(int pair_count, ...) {
    if (pair_count <= 0) return 0.0;
    
    va_list args;
    va_start(args, pair_count);
    
    double weighted_sum = 0.0;
    double weight_sum = 0.0;
    
    for (int i = 0; i < pair_count; i++) {
        double value = va_arg(args, double);
        double weight = va_arg(args, double);
        weighted_sum += value * weight;
        weight_sum += weight;
    }
    
    va_end(args);
    
    if (weight_sum == 0.0) return 0.0;
    return weighted_sum / weight_sum;
}

/* Answer 9: Safe Array */
SafeArray *answer9_safe_array_create(int first, ...) {
    SafeArray *arr = malloc(sizeof(SafeArray));
    if (!arr) return NULL;
    
    arr->capacity = 10;
    arr->size = 0;
    arr->data = malloc(arr->capacity * sizeof(int));
    
    if (!arr->data) {
        free(arr);
        return NULL;
    }
    
    /* Add first element */
    if (first == -1) {
        return arr;
    }
    arr->data[arr->size++] = first;
    
    /* Add remaining elements */
    va_list args;
    va_start(args, first);
    
    int val;
    while ((val = va_arg(args, int)) != -1) {
        /* Resize if needed */
        if (arr->size >= arr->capacity) {
            arr->capacity *= 2;
            int *new_data = realloc(arr->data, arr->capacity * sizeof(int));
            if (!new_data) {
                va_end(args);
                free(arr->data);
                free(arr);
                return NULL;
            }
            arr->data = new_data;
        }
        arr->data[arr->size++] = val;
    }
    
    va_end(args);
    return arr;
}

/* Answer 10: Safe Printf */
int answer10_safe_printf(const char *format, ...) {
    if (format == NULL) return -1;
    
    va_list args;
    va_start(args, format);
    
    int count = 0;
    
    for (const char *p = format; *p; p++) {
        if (*p != '%') {
            putchar(*p);
            count++;
            continue;
        }
        
        p++;
        if (*p == '\0') {
            va_end(args);
            return -1;  /* Format ends with % */
        }
        
        switch (*p) {
            case 'd': {
                int val = va_arg(args, int);
                count += printf("%d", val);
                break;
            }
            case 'f': {
                double val = va_arg(args, double);
                count += printf("%f", val);
                break;
            }
            case 's': {
                char *val = va_arg(args, char*);
                if (val == NULL) val = "(null)";
                count += printf("%s", val);
                break;
            }
            case 'c': {
                int val = va_arg(args, int);
                putchar(val);
                count++;
                break;
            }
            case '%':
                putchar('%');
                count++;
                break;
            default:
                va_end(args);
                return -1;  /* Unknown format specifier */
        }
    }
    
    va_end(args);
    return count;
}

void run_answers(void) {
    printf("\n========== ANSWERS ==========\n\n");
    
    printf("Answer 1: Product\n");
    printf("  product(3, 2, 3, 4) = %d\n", answer1_product(3, 2, 3, 4));
    printf("  product(4, 1, 2, 3, 4) = %d\n\n", answer1_product(4, 1, 2, 3, 4));
    
    printf("Answer 2: String Join\n");
    char *s = answer2_join_strings(", ", "apple", "banana", "cherry", NULL);
    printf("  Result: \"%s\"\n\n", s);
    free(s);
    
    printf("Answer 3: Count in Range\n");
    printf("  count_in_range(5, 15, 6, 3, 7, 12, 18, 9, 2) = %d\n\n",
           answer3_count_in_range(5, 15, 6, 3, 7, 12, 18, 9, 2));
    
    printf("Answer 4: Debug Logger\n");
    answer4_debug_log(0, "Value: %d", 42);
    answer4_debug_log(3, "Error: %s", "connection failed");
    printf("\n");
    
    printf("Answer 5: Geometric Mean\n");
    printf("  geometric_mean(2, 2.0, 8.0) = %.2f\n\n",
           answer5_geometric_mean(2, 2.0, 8.0));
    
    printf("Answer 6: Table Row\n");
    answer6_print_table_row("sis", "Alice", 25, "Engineer");
    answer6_print_table_row("sfs", "Bob", 55000.50, "Manager");
    printf("\n");
    
    printf("Answer 7: All/Any True\n");
    printf("  all_true(3, 1, 1, 1) = %d\n", answer7_all_true(3, 1, 1, 1));
    printf("  all_true(3, 1, 0, 1) = %d\n", answer7_all_true(3, 1, 0, 1));
    printf("  any_true(3, 0, 1, 0) = %d\n", answer7_any_true(3, 0, 1, 0));
    printf("  any_true(3, 0, 0, 0) = %d\n\n", answer7_any_true(3, 0, 0, 0));
    
    printf("Answer 8: Weighted Average\n");
    printf("  weighted_average(3, 90.0, 0.3, 80.0, 0.3, 70.0, 0.4) = %.2f\n\n",
           answer8_weighted_average(3, 90.0, 0.3, 80.0, 0.3, 70.0, 0.4));
    
    printf("Answer 9: Safe Array\n");
    SafeArray *arr = answer9_safe_array_create(10, 20, 30, 40, 50, -1);
    if (arr) {
        printf("  Array (%zu elements): ", arr->size);
        for (size_t i = 0; i < arr->size; i++) {
            printf("%d ", arr->data[i]);
        }
        printf("\n\n");
        safe_array_free(arr);
    }
    
    printf("Answer 10: Safe Printf\n");
    int n = answer10_safe_printf("  Name: %s, Age: %d\n", "Alice", 25);
    printf("  (returned: %d)\n\n", n);
}

#endif /* SHOW_ANSWERS */


/* ============================================================
 * MAIN - Test Harness
 * ============================================================ */

void print_menu(void) {
    printf("Variable Arguments - Exercises\n");
    printf("===============================\n\n");
    printf("Select an exercise:\n\n");
    printf("  1.  Product of Integers\n");
    printf("  2.  String Join with Delimiter\n");
    printf("  3.  Count Values in Range\n");
    printf("  4.  Custom Debug Logger\n");
    printf("  5.  Geometric Mean\n");
    printf("  6.  Format Table Row\n");
    printf("  7.  All True / Any True\n");
    printf("  8.  Weighted Average\n");
    printf("  9.  Safe Array Builder\n");
    printf("  10. Printf with Validation\n");
    printf("  0.  Run all exercises\n");
    printf("\n");
    
#ifdef SHOW_ANSWERS
    printf("  (Answers available - compiled with -DSHOW_ANSWERS)\n\n");
#else
    printf("  (Compile with -DSHOW_ANSWERS to see solutions)\n\n");
#endif
}

int main(int argc, char *argv[]) {
    int choice = -1;
    
    if (argc < 2) {
        print_menu();
        printf("Enter exercise number: ");
        if (scanf("%d", &choice) != 1) {
            printf("Invalid input\n");
            return 1;
        }
        printf("\n");
    } else {
        choice = atoi(argv[1]);
    }
    
    switch (choice) {
        case 0:
            exercise1_product();
            exercise2_join_strings();
            exercise3_count_range();
            exercise4_debug_logger();
            exercise5_geometric_mean();
            exercise6_table_row();
            exercise7_all_any_true();
            exercise8_weighted_average();
            exercise9_safe_array();
            exercise10_safe_printf();
#ifdef SHOW_ANSWERS
            run_answers();
#endif
            break;
        case 1:  exercise1_product(); break;
        case 2:  exercise2_join_strings(); break;
        case 3:  exercise3_count_range(); break;
        case 4:  exercise4_debug_logger(); break;
        case 5:  exercise5_geometric_mean(); break;
        case 6:  exercise6_table_row(); break;
        case 7:  exercise7_all_any_true(); break;
        case 8:  exercise8_weighted_average(); break;
        case 9:  exercise9_safe_array(); break;
        case 10: exercise10_safe_printf(); break;
        default:
            printf("Invalid choice. Run without arguments to see menu.\n");
            return 1;
    }
    
#ifdef SHOW_ANSWERS
    if (choice >= 1 && choice <= 10) {
        printf("\n--- Answer for Exercise %d ---\n", choice);
        run_answers();
    }
#endif
    
    return 0;
}
Exercises - C Programming Tutorial | DeepML