c
exercises
exercises.c🔧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;
}