c

exercises

exercises.c🔧
/**
 * =============================================================================
 * Macros and Definitions in C - Exercises
 * =============================================================================
 * 
 * Practice exercises for understanding and applying C preprocessor macros.
 * Complete each exercise in the designated space.
 * 
 * Compile: gcc -Wall -Wextra -std=c99 -o exercises exercises.c
 * Run: ./exercises
 * =============================================================================
 */

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

// =============================================================================
// Exercise 1: Basic Object-like Macros
// =============================================================================
/**
 * Define the following macros:
 * 1. GRAVITY - acceleration due to gravity (9.81 m/s²)
 * 2. SPEED_OF_LIGHT - speed of light in m/s (299792458)
 * 3. MAX_USERNAME_LEN - maximum username length (32)
 * 4. DEFAULT_TIMEOUT - default timeout in seconds (30)
 * 5. APP_NAME - application name as "MacroExercises"
 * 
 * Then use them in the function below to print their values.
 */

// YOUR CODE HERE: Define the macros


void exercise1(void) {
    printf("=== Exercise 1: Basic Object-like Macros ===\n");
    
    // YOUR CODE HERE: Print the values of each macro
    // Example: printf("Gravity: %.2f m/s²\n", GRAVITY);
    
    printf("\n");
}

// =============================================================================
// Exercise 2: Function-like Macros for Math Operations
// =============================================================================
/**
 * Define the following function-like macros:
 * 1. SQUARE(x) - returns x squared
 * 2. AVERAGE(a, b) - returns average of a and b
 * 3. IS_EVEN(n) - returns 1 if n is even, 0 otherwise
 * 4. IS_POSITIVE(x) - returns 1 if x > 0, 0 otherwise
 * 5. CELSIUS_TO_FAHRENHEIT(c) - converts Celsius to Fahrenheit (F = C * 9/5 + 32)
 * 
 * Remember to use proper parentheses!
 */

// YOUR CODE HERE: Define the macros


void exercise2(void) {
    printf("=== Exercise 2: Function-like Macros ===\n");
    
    // Test SQUARE
    printf("SQUARE(5) = %d\n", 0);  // Should be 25
    printf("SQUARE(3 + 2) = %d\n", 0);  // Should be 25, not 11
    
    // Test AVERAGE
    printf("AVERAGE(10, 20) = %.2f\n", 0.0);  // Should be 15.0
    
    // Test IS_EVEN
    printf("IS_EVEN(4) = %d\n", 0);  // Should be 1
    printf("IS_EVEN(7) = %d\n", 0);  // Should be 0
    
    // Test IS_POSITIVE
    printf("IS_POSITIVE(5) = %d\n", 0);   // Should be 1
    printf("IS_POSITIVE(-3) = %d\n", 0);  // Should be 0
    
    // Test CELSIUS_TO_FAHRENHEIT
    printf("CELSIUS_TO_FAHRENHEIT(0) = %.2f\n", 0.0);    // Should be 32.0
    printf("CELSIUS_TO_FAHRENHEIT(100) = %.2f\n", 0.0);  // Should be 212.0
    
    printf("\n");
}

// =============================================================================
// Exercise 3: Multi-statement Macros
// =============================================================================
/**
 * Define the following multi-statement macros using do { } while(0):
 * 
 * 1. SWAP_DOUBLE(a, b) - swaps two double values
 * 
 * 2. PRINT_RANGE(start, end) - prints numbers from start to end (inclusive)
 * 
 * 3. SAFE_STRCPY(dest, src, size) - safely copies string with size limit
 *    and ensures null termination
 */

// YOUR CODE HERE: Define the macros


void exercise3(void) {
    printf("=== Exercise 3: Multi-statement Macros ===\n");
    
    // Test SWAP_DOUBLE
    double x = 3.14, y = 2.71;
    printf("Before swap: x = %.2f, y = %.2f\n", x, y);
    // SWAP_DOUBLE(x, y);  // Uncomment after implementing
    printf("After swap:  x = %.2f, y = %.2f\n", x, y);
    printf("\n");
    
    // Test PRINT_RANGE
    printf("PRINT_RANGE(1, 5): ");
    // PRINT_RANGE(1, 5);  // Uncomment after implementing
    printf("\n\n");
    
    // Test SAFE_STRCPY
    char buffer[10];
    const char *long_string = "This is a very long string";
    // SAFE_STRCPY(buffer, long_string, sizeof(buffer));  // Uncomment
    printf("SAFE_STRCPY result: %s\n", buffer);
    
    printf("\n");
}

// =============================================================================
// Exercise 4: Stringification (#) Operator
// =============================================================================
/**
 * Define the following macros using stringification:
 * 
 * 1. VAR_TO_STRING(var) - converts variable name to string
 * 
 * 2. PRINT_INT(var) - prints "var = <value>" for an integer variable
 * 
 * 3. PRINT_DOUBLE(var) - prints "var = <value>" for a double variable
 * 
 * 4. ASSERT_TRUE(cond) - if cond is false, prints the condition as string
 *    and the file/line number
 */

// YOUR CODE HERE: Define the macros


void exercise4(void) {
    printf("=== Exercise 4: Stringification Operator ===\n");
    
    int count = 42;
    double pi = 3.14159;
    
    // Test VAR_TO_STRING
    // printf("Variable name: %s\n", VAR_TO_STRING(count));
    
    // Test PRINT_INT
    // PRINT_INT(count);
    
    // Test PRINT_DOUBLE
    // PRINT_DOUBLE(pi);
    
    // Test ASSERT_TRUE
    int value = 10;
    // ASSERT_TRUE(value > 0);   // Should pass silently
    // ASSERT_TRUE(value > 100); // Should print failure message
    
    printf("\n");
}

// =============================================================================
// Exercise 5: Token Pasting (##) Operator
// =============================================================================
/**
 * Define the following macros using token pasting:
 * 
 * 1. MAKE_FUNCTION_NAME(prefix, suffix) - creates a function name
 *    Example: MAKE_FUNCTION_NAME(calc, sum) -> calc_sum
 * 
 * 2. DECLARE_COUNTER(name) - declares a static int counter named name_counter
 *    and a function increment_name() that increments and returns it
 * 
 * 3. CREATE_PAIR(type, name) - creates two variables: name_first and name_second
 */

// YOUR CODE HERE: Define the macros


void exercise5(void) {
    printf("=== Exercise 5: Token Pasting Operator ===\n");
    
    // Test CREATE_PAIR
    // CREATE_PAIR(int, coord);
    // coord_first = 10;
    // coord_second = 20;
    // printf("Coordinates: (%d, %d)\n", coord_first, coord_second);
    
    // Test DECLARE_COUNTER (would need to be outside function)
    // Call increment function and print result
    
    printf("\n");
}

// =============================================================================
// Exercise 6: Variadic Macros
// =============================================================================
/**
 * Define the following variadic macros:
 * 
 * 1. PRINT(...) - simple printf wrapper
 * 
 * 2. LOG_MESSAGE(level, format, ...) - prints "[LEVEL] message"
 *    where level is a string like "INFO", "WARN", "ERROR"
 * 
 * 3. DEBUG_PRINT(format, ...) - prints debug message with file and line
 *    Format: "[DEBUG file:line] message"
 */

// YOUR CODE HERE: Define the macros


void exercise6(void) {
    printf("=== Exercise 6: Variadic Macros ===\n");
    
    // Test PRINT
    // PRINT("Hello, World!\n");
    // PRINT("Value: %d\n", 42);
    
    // Test LOG_MESSAGE
    // LOG_MESSAGE("INFO", "Application started");
    // LOG_MESSAGE("ERROR", "Failed to open file: %s", "test.txt");
    
    // Test DEBUG_PRINT
    // DEBUG_PRINT("Processing item %d of %d", 5, 10);
    
    printf("\n");
}

// =============================================================================
// Exercise 7: Array Utility Macros
// =============================================================================
/**
 * Define the following array utility macros:
 * 
 * 1. ARRAY_LEN(arr) - returns the number of elements in an array
 * 
 * 2. ARRAY_LAST(arr) - returns the last element of an array
 * 
 * 3. ARRAY_FIRST(arr) - returns the first element of an array
 * 
 * 4. IN_RANGE(val, min, max) - returns 1 if val is between min and max (inclusive)
 * 
 * 5. PRINT_ARRAY_INT(arr, size) - prints all elements of an int array
 */

// YOUR CODE HERE: Define the macros


void exercise7(void) {
    printf("=== Exercise 7: Array Utility Macros ===\n");
    
    int numbers[] = {10, 20, 30, 40, 50};
    
    // Test ARRAY_LEN
    // printf("Array length: %zu\n", ARRAY_LEN(numbers));
    
    // Test ARRAY_FIRST and ARRAY_LAST
    // printf("First element: %d\n", ARRAY_FIRST(numbers));
    // printf("Last element: %d\n", ARRAY_LAST(numbers));
    
    // Test IN_RANGE
    int value = 25;
    // printf("%d in range [20, 30]: %d\n", value, IN_RANGE(value, 20, 30));
    // printf("%d in range [1, 10]: %d\n", value, IN_RANGE(value, 1, 10));
    
    // Test PRINT_ARRAY_INT
    // printf("Array: ");
    // PRINT_ARRAY_INT(numbers, ARRAY_LEN(numbers));
    
    printf("\n");
}

// =============================================================================
// Exercise 8: Bit Manipulation Macros
// =============================================================================
/**
 * Define the following bit manipulation macros:
 * 
 * 1. BIT_SET(n, pos) - sets bit at position pos in n
 * 2. BIT_CLEAR(n, pos) - clears bit at position pos in n
 * 3. BIT_TOGGLE(n, pos) - toggles bit at position pos in n
 * 4. BIT_CHECK(n, pos) - returns 1 if bit at pos is set, 0 otherwise
 * 5. BITMASK(n) - creates a bitmask with n lower bits set (e.g., BITMASK(3) = 0b111 = 7)
 */

// YOUR CODE HERE: Define the macros


void exercise8(void) {
    printf("=== Exercise 8: Bit Manipulation Macros ===\n");
    
    unsigned char value = 0b00001010;  // 10 in decimal
    
    printf("Original value: %d (0b%08b)\n", value, value);
    
    // Test BIT_SET
    // printf("After BIT_SET(value, 0): %d\n", BIT_SET(value, 0));  // Should be 11
    
    // Test BIT_CLEAR
    // printf("After BIT_CLEAR(value, 1): %d\n", BIT_CLEAR(value, 1));  // Should be 8
    
    // Test BIT_TOGGLE
    // printf("After BIT_TOGGLE(value, 3): %d\n", BIT_TOGGLE(value, 3));  // Should be 2
    
    // Test BIT_CHECK
    // printf("BIT_CHECK(value, 1): %d\n", BIT_CHECK(value, 1));  // Should be 1
    // printf("BIT_CHECK(value, 0): %d\n", BIT_CHECK(value, 0));  // Should be 0
    
    // Test BITMASK
    // printf("BITMASK(4): %d\n", BITMASK(4));  // Should be 15 (0b1111)
    
    printf("\n");
}

// =============================================================================
// Exercise 9: Safe Memory Macros
// =============================================================================
/**
 * Define the following memory-related macros:
 * 
 * 1. SAFE_MALLOC(ptr, type, count) - allocates memory and checks for NULL
 *    If allocation fails, prints error and sets ptr to NULL
 * 
 * 2. SAFE_REALLOC(ptr, type, count) - reallocates memory safely
 * 
 * 3. SAFE_FREE(ptr) - frees memory and sets pointer to NULL
 * 
 * 4. ZERO_STRUCT(s) - zeros out a structure
 */

// YOUR CODE HERE: Define the macros


void exercise9(void) {
    printf("=== Exercise 9: Safe Memory Macros ===\n");
    
    // Test SAFE_MALLOC
    int *arr = NULL;
    // SAFE_MALLOC(arr, int, 5);
    
    if (arr) {
        for (int i = 0; i < 5; i++) {
            arr[i] = (i + 1) * 10;
        }
        printf("Allocated array: ");
        for (int i = 0; i < 5; i++) {
            printf("%d ", arr[i]);
        }
        printf("\n");
        
        // Test SAFE_FREE
        // SAFE_FREE(arr);
        // printf("After SAFE_FREE, arr is: %p\n", (void *)arr);
    }
    
    // Test ZERO_STRUCT
    struct Point {
        int x, y, z;
    } point = {10, 20, 30};
    
    printf("Before ZERO_STRUCT: (%d, %d, %d)\n", point.x, point.y, point.z);
    // ZERO_STRUCT(point);
    printf("After ZERO_STRUCT: (%d, %d, %d)\n", point.x, point.y, point.z);
    
    printf("\n");
}

// =============================================================================
// Exercise 10: Build Your Own Assert System
// =============================================================================
/**
 * Create a comprehensive assertion system with these macros:
 * 
 * 1. ASSERT(cond) - basic assertion that prints condition and location
 * 
 * 2. ASSERT_EQ(a, b) - asserts that a equals b
 * 
 * 3. ASSERT_NE(a, b) - asserts that a does not equal b
 * 
 * 4. ASSERT_GT(a, b) - asserts that a is greater than b
 * 
 * 5. ASSERT_NULL(ptr) - asserts that ptr is NULL
 * 
 * 6. ASSERT_NOT_NULL(ptr) - asserts that ptr is not NULL
 * 
 * All assertions should:
 * - Print the file and line number on failure
 * - Print the expression that failed
 * - Not terminate the program (soft assertions)
 */

// YOUR CODE HERE: Define the macros


void exercise10(void) {
    printf("=== Exercise 10: Custom Assert System ===\n");
    
    int a = 10, b = 20;
    
    // Test assertions
    // ASSERT(a > 0);          // Should pass
    // ASSERT(a > 100);        // Should fail
    
    // ASSERT_EQ(a, 10);       // Should pass
    // ASSERT_EQ(a, b);        // Should fail
    
    // ASSERT_NE(a, b);        // Should pass
    // ASSERT_NE(a, 10);       // Should fail
    
    // ASSERT_GT(b, a);        // Should pass
    // ASSERT_GT(a, b);        // Should fail
    
    int *ptr = NULL;
    int *valid_ptr = &a;
    
    // ASSERT_NULL(ptr);       // Should pass
    // ASSERT_NULL(valid_ptr); // Should fail
    
    // ASSERT_NOT_NULL(valid_ptr);  // Should pass
    // ASSERT_NOT_NULL(ptr);        // Should fail
    
    printf("\n");
}

// =============================================================================
// Main Function
// =============================================================================

int main(void) {
    printf("============================================================\n");
    printf("      MACROS AND DEFINITIONS - EXERCISES                    \n");
    printf("============================================================\n\n");
    
    exercise1();
    exercise2();
    exercise3();
    exercise4();
    exercise5();
    exercise6();
    exercise7();
    exercise8();
    exercise9();
    exercise10();
    
    printf("============================================================\n");
    printf("Complete the exercises by implementing the required macros!\n");
    printf("============================================================\n");
    
    return 0;
}

// =============================================================================
// ANSWER KEY
// =============================================================================
/*
 * Below are the solutions. Try to solve the exercises yourself first!
 */

/*
// Exercise 1: Basic Object-like Macros
#define GRAVITY 9.81
#define SPEED_OF_LIGHT 299792458
#define MAX_USERNAME_LEN 32
#define DEFAULT_TIMEOUT 30
#define APP_NAME "MacroExercises"

// Exercise 2: Function-like Macros
#define SQUARE(x) ((x) * (x))
#define AVERAGE(a, b) (((a) + (b)) / 2.0)
#define IS_EVEN(n) (((n) % 2) == 0)
#define IS_POSITIVE(x) ((x) > 0)
#define CELSIUS_TO_FAHRENHEIT(c) (((c) * 9.0 / 5.0) + 32)

// Exercise 3: Multi-statement Macros
#define SWAP_DOUBLE(a, b) do { \
    double _temp = (a); \
    (a) = (b); \
    (b) = _temp; \
} while(0)

#define PRINT_RANGE(start, end) do { \
    for (int _i = (start); _i <= (end); _i++) { \
        printf("%d ", _i); \
    } \
} while(0)

#define SAFE_STRCPY(dest, src, size) do { \
    strncpy((dest), (src), (size) - 1); \
    (dest)[(size) - 1] = '\0'; \
} while(0)

// Exercise 4: Stringification Operator
#define VAR_TO_STRING(var) #var
#define PRINT_INT(var) printf(#var " = %d\n", (var))
#define PRINT_DOUBLE(var) printf(#var " = %.6f\n", (var))
#define ASSERT_TRUE(cond) do { \
    if (!(cond)) { \
        printf("Assertion failed: %s\n", #cond); \
        printf("  File: %s, Line: %d\n", __FILE__, __LINE__); \
    } \
} while(0)

// Exercise 5: Token Pasting Operator
#define MAKE_FUNCTION_NAME(prefix, suffix) prefix##_##suffix
#define DECLARE_COUNTER(name) \
    static int name##_counter = 0; \
    int increment_##name(void) { return ++name##_counter; }
#define CREATE_PAIR(type, name) type name##_first, name##_second

// Exercise 6: Variadic Macros
#define PRINT(...) printf(__VA_ARGS__)
#define LOG_MESSAGE(level, format, ...) \
    printf("[%s] " format "\n", level, ##__VA_ARGS__)
#define DEBUG_PRINT(format, ...) \
    printf("[DEBUG %s:%d] " format "\n", __FILE__, __LINE__, ##__VA_ARGS__)

// Exercise 7: Array Utility Macros
#define ARRAY_LEN(arr) (sizeof(arr) / sizeof((arr)[0]))
#define ARRAY_LAST(arr) ((arr)[ARRAY_LEN(arr) - 1])
#define ARRAY_FIRST(arr) ((arr)[0])
#define IN_RANGE(val, min, max) ((val) >= (min) && (val) <= (max))
#define PRINT_ARRAY_INT(arr, size) do { \
    printf("["); \
    for (size_t _i = 0; _i < (size); _i++) { \
        if (_i > 0) printf(", "); \
        printf("%d", (arr)[_i]); \
    } \
    printf("]\n"); \
} while(0)

// Exercise 8: Bit Manipulation Macros
#define BIT_SET(n, pos) ((n) | (1 << (pos)))
#define BIT_CLEAR(n, pos) ((n) & ~(1 << (pos)))
#define BIT_TOGGLE(n, pos) ((n) ^ (1 << (pos)))
#define BIT_CHECK(n, pos) (((n) >> (pos)) & 1)
#define BITMASK(n) ((1 << (n)) - 1)

// Exercise 9: Safe Memory Macros
#define SAFE_MALLOC(ptr, type, count) do { \
    (ptr) = (type *)malloc(sizeof(type) * (count)); \
    if ((ptr) == NULL) { \
        fprintf(stderr, "Memory allocation failed at %s:%d\n", \
                __FILE__, __LINE__); \
    } \
} while(0)

#define SAFE_REALLOC(ptr, type, count) do { \
    type *_new_ptr = (type *)realloc((ptr), sizeof(type) * (count)); \
    if (_new_ptr == NULL) { \
        fprintf(stderr, "Reallocation failed at %s:%d\n", \
                __FILE__, __LINE__); \
    } else { \
        (ptr) = _new_ptr; \
    } \
} while(0)

#define SAFE_FREE(ptr) do { \
    if ((ptr) != NULL) { \
        free(ptr); \
        (ptr) = NULL; \
    } \
} while(0)

#define ZERO_STRUCT(s) memset(&(s), 0, sizeof(s))

// Exercise 10: Assert System
#define ASSERT(cond) do { \
    if (!(cond)) { \
        fprintf(stderr, "ASSERT FAILED: %s\n", #cond); \
        fprintf(stderr, "  Location: %s:%d\n", __FILE__, __LINE__); \
    } \
} while(0)

#define ASSERT_EQ(a, b) do { \
    if ((a) != (b)) { \
        fprintf(stderr, "ASSERT_EQ FAILED: %s == %s\n", #a, #b); \
        fprintf(stderr, "  Location: %s:%d\n", __FILE__, __LINE__); \
    } \
} while(0)

#define ASSERT_NE(a, b) do { \
    if ((a) == (b)) { \
        fprintf(stderr, "ASSERT_NE FAILED: %s != %s\n", #a, #b); \
        fprintf(stderr, "  Location: %s:%d\n", __FILE__, __LINE__); \
    } \
} while(0)

#define ASSERT_GT(a, b) do { \
    if (!((a) > (b))) { \
        fprintf(stderr, "ASSERT_GT FAILED: %s > %s\n", #a, #b); \
        fprintf(stderr, "  Location: %s:%d\n", __FILE__, __LINE__); \
    } \
} while(0)

#define ASSERT_NULL(ptr) do { \
    if ((ptr) != NULL) { \
        fprintf(stderr, "ASSERT_NULL FAILED: %s is not NULL\n", #ptr); \
        fprintf(stderr, "  Location: %s:%d\n", __FILE__, __LINE__); \
    } \
} while(0)

#define ASSERT_NOT_NULL(ptr) do { \
    if ((ptr) == NULL) { \
        fprintf(stderr, "ASSERT_NOT_NULL FAILED: %s is NULL\n", #ptr); \
        fprintf(stderr, "  Location: %s:%d\n", __FILE__, __LINE__); \
    } \
} while(0)
*/
Exercises - C Programming Tutorial | DeepML