c

exercises

exercises.c🔧
/**
 * Command Line Arguments in C - Exercises
 * 
 * Practice problems for working with command line arguments.
 * 
 * Compilation:
 *   gcc -Wall -o exercises exercises.c
 *   gcc -Wall -D_GNU_SOURCE -o exercises exercises.c  (for getopt_long)
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <getopt.h>

/* ============================================================
 * EXERCISE 1: Argument Echo
 * ============================================================
 * 
 * Write a program that echoes all command line arguments,
 * one per line, with their index.
 * 
 * Expected output for: ./exercise1 hello world 123
 * 
 *   Argument 0: ./exercise1
 *   Argument 1: hello
 *   Argument 2: world
 *   Argument 3: 123
 *   Total arguments: 4
 */

void exercise1_argument_echo(int argc, char *argv[]) {
    printf("Exercise 1: Argument Echo\n");
    printf("--------------------------\n");
    
    /* TODO: Implement argument echo */
    /* Print each argument with its index */
    /* Print total argument count at the end */
    
    printf("\n");
}

/* ============================================================
 * EXERCISE 2: Reverse Arguments
 * ============================================================
 * 
 * Write a program that prints all arguments (excluding program name)
 * in reverse order.
 * 
 * Expected output for: ./exercise2 one two three
 * 
 *   three
 *   two
 *   one
 */

void exercise2_reverse_arguments(int argc, char *argv[]) {
    printf("Exercise 2: Reverse Arguments\n");
    printf("------------------------------\n");
    
    /* TODO: Print arguments in reverse order */
    /* Skip argv[0] (program name) */
    
    printf("\n");
}

/* ============================================================
 * EXERCISE 3: Sum of Numbers
 * ============================================================
 * 
 * Write a program that calculates the sum of all numeric
 * arguments passed on the command line.
 * 
 * Expected output for: ./exercise3 10 20 30
 * 
 *   10 + 20 + 30 = 60
 * 
 * Handle invalid numbers gracefully.
 */

void exercise3_sum_numbers(int argc, char *argv[]) {
    printf("Exercise 3: Sum of Numbers\n");
    printf("--------------------------\n");
    
    /* TODO: Sum all valid numeric arguments */
    /* Use strtol for safe conversion */
    /* Skip invalid numbers with a warning */
    
    printf("\n");
}

/* ============================================================
 * EXERCISE 4: Find Longest Argument
 * ============================================================
 * 
 * Write a program that finds and prints the longest
 * command line argument.
 * 
 * Expected output for: ./exercise4 short verylongargument mid
 * 
 *   Longest argument: "verylongargument" (16 characters)
 */

void exercise4_longest_argument(int argc, char *argv[]) {
    printf("Exercise 4: Find Longest Argument\n");
    printf("----------------------------------\n");
    
    /* TODO: Find the longest argument */
    /* Consider whether to include program name */
    
    printf("\n");
}

/* ============================================================
 * EXERCISE 5: Simple grep
 * ============================================================
 * 
 * Write a program that searches for a pattern in files.
 * 
 * Usage: ./exercise5 <pattern> <file1> [file2] ...
 * 
 * Expected output:
 *   filename:line_number:matching_line
 */

void exercise5_simple_grep(int argc, char *argv[]) {
    printf("Exercise 5: Simple grep\n");
    printf("------------------------\n");
    
    /* TODO: Implement simple grep */
    /* Pattern is argv[1] */
    /* Files are argv[2], argv[3], ... */
    /* Print matching lines with filename and line number */
    
    printf("\n");
}

/* ============================================================
 * EXERCISE 6: Option Parser
 * ============================================================
 * 
 * Write a program with the following options using getopt:
 * 
 *   -h        Show help
 *   -v        Verbose mode
 *   -n NUM    Set count to NUM
 *   -o FILE   Output file
 * 
 * Print the parsed values.
 */

void exercise6_option_parser(int argc, char *argv[]) {
    printf("Exercise 6: Option Parser\n");
    printf("--------------------------\n");
    
    /* TODO: Implement option parsing with getopt */
    /* Parse -h, -v, -n, -o options */
    /* Print final configuration */
    
    printf("\n");
}

/* ============================================================
 * EXERCISE 7: Long Options
 * ============================================================
 * 
 * Extend exercise 6 to support long options:
 * 
 *   -h, --help      Show help
 *   -v, --verbose   Verbose mode
 *   -n, --number    Set count
 *   -o, --output    Output file
 *   --version       Show version
 */

void exercise7_long_options(int argc, char *argv[]) {
    printf("Exercise 7: Long Options\n");
    printf("-------------------------\n");
    
    /* TODO: Implement with getopt_long */
    /* Support both short and long options */
    
    printf("\n");
}

/* ============================================================
 * EXERCISE 8: File Statistics
 * ============================================================
 * 
 * Write a wc-like program that counts lines, words, and characters.
 * 
 * Usage: ./exercise8 [-l] [-w] [-c] [file...]
 * 
 *   -l  Count lines only
 *   -w  Count words only
 *   -c  Count characters only
 *   (default: all three)
 */

void exercise8_file_stats(int argc, char *argv[]) {
    printf("Exercise 8: File Statistics\n");
    printf("----------------------------\n");
    
    /* TODO: Implement wc-like functionality */
    /* Support -l, -w, -c options */
    /* Read from stdin if no file given */
    
    printf("\n");
}

/* ============================================================
 * EXERCISE 9: Environment Config
 * ============================================================
 * 
 * Write a program that reads configuration from both
 * environment variables and command line arguments.
 * Command line should override environment.
 * 
 * ENV: MY_APP_DEBUG, MY_APP_OUTPUT
 * CLI: -d (debug), -o FILE (output)
 */

void exercise9_env_config(int argc, char *argv[]) {
    printf("Exercise 9: Environment Config\n");
    printf("-------------------------------\n");
    
    /* TODO: Read config from environment first */
    /* Then override with command line arguments */
    /* Display final configuration */
    
    printf("\n");
}

/* ============================================================
 * EXERCISE 10: Subcommand Parser
 * ============================================================
 * 
 * Implement a git-like subcommand interface:
 * 
 *   ./exercise10 init
 *   ./exercise10 add <file>
 *   ./exercise10 remove <file>
 *   ./exercise10 list [-a]
 *   ./exercise10 help [command]
 */

void exercise10_subcommands(int argc, char *argv[]) {
    printf("Exercise 10: Subcommand Parser\n");
    printf("-------------------------------\n");
    
    /* TODO: Implement subcommand parsing */
    /* Each subcommand may have its own options */
    
    printf("\n");
}


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

#ifdef SHOW_ANSWERS

/* Answer 1: Argument Echo */
void answer1_argument_echo(int argc, char *argv[]) {
    printf("Answer 1: Argument Echo\n");
    printf("-----------------------\n");
    
    for (int i = 0; i < argc; i++) {
        printf("Argument %d: %s\n", i, argv[i]);
    }
    printf("Total arguments: %d\n", argc);
    printf("\n");
}

/* Answer 2: Reverse Arguments */
void answer2_reverse_arguments(int argc, char *argv[]) {
    printf("Answer 2: Reverse Arguments\n");
    printf("----------------------------\n");
    
    for (int i = argc - 1; i >= 1; i--) {
        printf("%s\n", argv[i]);
    }
    printf("\n");
}

/* Answer 3: Sum of Numbers */
void answer3_sum_numbers(int argc, char *argv[]) {
    printf("Answer 3: Sum of Numbers\n");
    printf("-------------------------\n");
    
    if (argc < 2) {
        printf("Usage: %s <num1> [num2] [num3] ...\n", argv[0]);
        return;
    }
    
    long sum = 0;
    int first = 1;
    
    for (int i = 1; i < argc; i++) {
        char *endptr;
        errno = 0;
        long val = strtol(argv[i], &endptr, 10);
        
        if (*endptr != '\0' || errno == ERANGE) {
            fprintf(stderr, "Warning: '%s' is not a valid number\n", argv[i]);
            continue;
        }
        
        if (!first) {
            printf(" + ");
        }
        printf("%ld", val);
        first = 0;
        
        sum += val;
    }
    
    printf(" = %ld\n", sum);
    printf("\n");
}

/* Answer 4: Find Longest Argument */
void answer4_longest_argument(int argc, char *argv[]) {
    printf("Answer 4: Find Longest Argument\n");
    printf("--------------------------------\n");
    
    if (argc < 2) {
        printf("No arguments provided\n");
        return;
    }
    
    char *longest = argv[1];
    size_t max_len = strlen(argv[1]);
    
    for (int i = 2; i < argc; i++) {
        size_t len = strlen(argv[i]);
        if (len > max_len) {
            max_len = len;
            longest = argv[i];
        }
    }
    
    printf("Longest argument: \"%s\" (%zu characters)\n", longest, max_len);
    printf("\n");
}

/* Answer 5: Simple grep */
void answer5_simple_grep(int argc, char *argv[]) {
    printf("Answer 5: Simple grep\n");
    printf("----------------------\n");
    
    if (argc < 3) {
        printf("Usage: %s <pattern> <file1> [file2] ...\n", argv[0]);
        return;
    }
    
    const char *pattern = argv[1];
    int total_matches = 0;
    
    for (int i = 2; i < argc; i++) {
        FILE *f = fopen(argv[i], "r");
        if (!f) {
            fprintf(stderr, "%s: %s: %s\n", argv[0], argv[i], strerror(errno));
            continue;
        }
        
        char line[1024];
        int line_num = 0;
        
        while (fgets(line, sizeof(line), f)) {
            line_num++;
            if (strstr(line, pattern)) {
                /* Remove trailing newline for clean output */
                size_t len = strlen(line);
                if (len > 0 && line[len-1] == '\n') {
                    line[len-1] = '\0';
                }
                printf("%s:%d:%s\n", argv[i], line_num, line);
                total_matches++;
            }
        }
        
        fclose(f);
    }
    
    printf("\nTotal matches: %d\n", total_matches);
    printf("\n");
}

/* Answer 6: Option Parser */
void answer6_option_parser(int argc, char *argv[]) {
    printf("Answer 6: Option Parser\n");
    printf("------------------------\n");
    
    /* Reset getopt */
    optind = 1;
    opterr = 1;
    
    int verbose = 0;
    int number = 0;
    char *output = NULL;
    int opt;
    
    while ((opt = getopt(argc, argv, "hvn:o:")) != -1) {
        switch (opt) {
            case 'h':
                printf("Usage: %s [-h] [-v] [-n NUM] [-o FILE]\n", argv[0]);
                printf("Options:\n");
                printf("  -h        Show this help\n");
                printf("  -v        Verbose mode\n");
                printf("  -n NUM    Set count to NUM\n");
                printf("  -o FILE   Output to FILE\n");
                return;
            case 'v':
                verbose = 1;
                break;
            case 'n':
                number = atoi(optarg);
                break;
            case 'o':
                output = optarg;
                break;
            case '?':
                return;
        }
    }
    
    printf("Configuration:\n");
    printf("  Verbose: %s\n", verbose ? "yes" : "no");
    printf("  Number: %d\n", number);
    printf("  Output: %s\n", output ? output : "(stdout)");
    
    if (optind < argc) {
        printf("  Extra arguments: ");
        for (int i = optind; i < argc; i++) {
            printf("%s ", argv[i]);
        }
        printf("\n");
    }
    printf("\n");
}

/* Answer 7: Long Options */
void answer7_long_options(int argc, char *argv[]) {
    printf("Answer 7: Long Options\n");
    printf("-----------------------\n");
    
    /* Reset getopt */
    optind = 1;
    opterr = 1;
    
    int verbose = 0;
    int number = 0;
    char *output = NULL;
    
    static struct option long_options[] = {
        {"help",    no_argument,       NULL, 'h'},
        {"verbose", no_argument,       NULL, 'v'},
        {"number",  required_argument, NULL, 'n'},
        {"output",  required_argument, NULL, 'o'},
        {"version", no_argument,       NULL, 'V'},
        {NULL,      0,                 NULL, 0}
    };
    
    int opt;
    while ((opt = getopt_long(argc, argv, "hvn:o:", 
                               long_options, NULL)) != -1) {
        switch (opt) {
            case 'h':
                printf("Usage: %s [OPTIONS]\n", argv[0]);
                printf("Options:\n");
                printf("  -h, --help       Show help\n");
                printf("  -v, --verbose    Verbose mode\n");
                printf("  -n, --number=N   Set number\n");
                printf("  -o, --output=F   Output file\n");
                printf("      --version    Show version\n");
                return;
            case 'v':
                verbose = 1;
                break;
            case 'n':
                number = atoi(optarg);
                break;
            case 'o':
                output = optarg;
                break;
            case 'V':
                printf("Version 1.0.0\n");
                return;
            case '?':
                return;
        }
    }
    
    printf("Configuration:\n");
    printf("  Verbose: %s\n", verbose ? "yes" : "no");
    printf("  Number: %d\n", number);
    printf("  Output: %s\n", output ? output : "(stdout)");
    printf("\n");
}

/* Answer 8: File Statistics */
void answer8_file_stats(int argc, char *argv[]) {
    printf("Answer 8: File Statistics\n");
    printf("--------------------------\n");
    
    /* Reset getopt */
    optind = 1;
    
    int show_lines = 0;
    int show_words = 0;
    int show_chars = 0;
    int opt;
    
    while ((opt = getopt(argc, argv, "lwc")) != -1) {
        switch (opt) {
            case 'l': show_lines = 1; break;
            case 'w': show_words = 1; break;
            case 'c': show_chars = 1; break;
            case '?': return;
        }
    }
    
    /* Default: show all */
    if (!show_lines && !show_words && !show_chars) {
        show_lines = show_words = show_chars = 1;
    }
    
    /* Process files */
    int file_count = argc - optind;
    long total_lines = 0, total_words = 0, total_chars = 0;
    
    for (int i = optind; i < argc || (i == optind && file_count == 0); i++) {
        FILE *f;
        const char *filename;
        
        if (file_count == 0 || (argc > optind && strcmp(argv[i], "-") == 0)) {
            f = stdin;
            filename = "(stdin)";
            if (file_count == 0) i = argc; /* Exit after stdin */
        } else {
            f = fopen(argv[i], "r");
            filename = argv[i];
            if (!f) {
                fprintf(stderr, "%s: %s\n", argv[i], strerror(errno));
                continue;
            }
        }
        
        long lines = 0, words = 0, chars = 0;
        int in_word = 0;
        int c;
        
        while ((c = fgetc(f)) != EOF) {
            chars++;
            if (c == '\n') lines++;
            if (isspace(c)) {
                in_word = 0;
            } else if (!in_word) {
                in_word = 1;
                words++;
            }
        }
        
        /* Print stats */
        if (show_lines) printf("%7ld ", lines);
        if (show_words) printf("%7ld ", words);
        if (show_chars) printf("%7ld ", chars);
        printf("%s\n", filename);
        
        total_lines += lines;
        total_words += words;
        total_chars += chars;
        
        if (f != stdin) fclose(f);
    }
    
    /* Print totals if multiple files */
    if (file_count > 1) {
        if (show_lines) printf("%7ld ", total_lines);
        if (show_words) printf("%7ld ", total_words);
        if (show_chars) printf("%7ld ", total_chars);
        printf("total\n");
    }
    printf("\n");
}

/* Answer 9: Environment Config */
void answer9_env_config(int argc, char *argv[]) {
    printf("Answer 9: Environment Config\n");
    printf("-----------------------------\n");
    
    /* Reset getopt */
    optind = 1;
    
    /* Read from environment first */
    int debug = 0;
    char *output = NULL;
    
    char *env_debug = getenv("MY_APP_DEBUG");
    if (env_debug && (strcmp(env_debug, "1") == 0 || 
                      strcasecmp(env_debug, "true") == 0)) {
        debug = 1;
    }
    
    char *env_output = getenv("MY_APP_OUTPUT");
    if (env_output) {
        output = env_output;
    }
    
    /* Override with command line */
    int opt;
    while ((opt = getopt(argc, argv, "do:")) != -1) {
        switch (opt) {
            case 'd':
                debug = 1;
                break;
            case 'o':
                output = optarg;
                break;
            case '?':
                return;
        }
    }
    
    printf("Configuration sources:\n");
    printf("  MY_APP_DEBUG = %s\n", env_debug ? env_debug : "(not set)");
    printf("  MY_APP_OUTPUT = %s\n", env_output ? env_output : "(not set)");
    printf("\nFinal configuration:\n");
    printf("  Debug: %s\n", debug ? "enabled" : "disabled");
    printf("  Output: %s\n", output ? output : "(stdout)");
    printf("\n");
}

/* Answer 10: Subcommand Parser */
void answer10_subcommands(int argc, char *argv[]) {
    printf("Answer 10: Subcommand Parser\n");
    printf("-----------------------------\n");
    
    if (argc < 2) {
        printf("Usage: %s <command> [options]\n\n", argv[0]);
        printf("Commands:\n");
        printf("  init              Initialize\n");
        printf("  add <file>        Add a file\n");
        printf("  remove <file>     Remove a file\n");
        printf("  list [-a]         List items\n");
        printf("  help [command]    Show help\n");
        return;
    }
    
    const char *command = argv[1];
    
    if (strcmp(command, "init") == 0) {
        printf("Initializing...\n");
        printf("Done.\n");
    }
    else if (strcmp(command, "add") == 0) {
        if (argc < 3) {
            printf("Usage: %s add <file>\n", argv[0]);
            return;
        }
        printf("Adding '%s'...\n", argv[2]);
        printf("Done.\n");
    }
    else if (strcmp(command, "remove") == 0 || strcmp(command, "rm") == 0) {
        if (argc < 3) {
            printf("Usage: %s remove <file>\n", argv[0]);
            return;
        }
        printf("Removing '%s'...\n", argv[2]);
        printf("Done.\n");
    }
    else if (strcmp(command, "list") == 0 || strcmp(command, "ls") == 0) {
        int show_all = 0;
        
        /* Parse list options */
        optind = 2;  /* Start after subcommand */
        int opt;
        while ((opt = getopt(argc, argv, "a")) != -1) {
            switch (opt) {
                case 'a':
                    show_all = 1;
                    break;
            }
        }
        
        printf("Listing items%s:\n", show_all ? " (including hidden)" : "");
        printf("  item1\n");
        printf("  item2\n");
        if (show_all) {
            printf("  .hidden_item\n");
        }
        printf("  item3\n");
    }
    else if (strcmp(command, "help") == 0) {
        if (argc >= 3) {
            printf("Help for '%s' command:\n\n", argv[2]);
            if (strcmp(argv[2], "init") == 0) {
                printf("init - Initialize the application\n");
                printf("Usage: %s init\n", argv[0]);
            } else if (strcmp(argv[2], "add") == 0) {
                printf("add - Add a file to the list\n");
                printf("Usage: %s add <filename>\n", argv[0]);
            } else if (strcmp(argv[2], "remove") == 0) {
                printf("remove - Remove a file from the list\n");
                printf("Usage: %s remove <filename>\n", argv[0]);
            } else if (strcmp(argv[2], "list") == 0) {
                printf("list - List all items\n");
                printf("Usage: %s list [-a]\n", argv[0]);
                printf("Options:\n");
                printf("  -a    Show all items including hidden\n");
            } else {
                printf("Unknown command: %s\n", argv[2]);
            }
        } else {
            printf("Use '%s help <command>' for more information\n", argv[0]);
        }
    }
    else {
        printf("Unknown command: %s\n", command);
        printf("Try '%s help' for usage information\n", argv[0]);
    }
    printf("\n");
}

#endif /* SHOW_ANSWERS */


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

void print_menu(void) {
    printf("Command Line Arguments - Exercises\n");
    printf("===================================\n\n");
    printf("Select an exercise:\n\n");
    printf("  1.  Argument Echo\n");
    printf("  2.  Reverse Arguments\n");
    printf("  3.  Sum of Numbers\n");
    printf("  4.  Find Longest Argument\n");
    printf("  5.  Simple grep\n");
    printf("  6.  Option Parser (getopt)\n");
    printf("  7.  Long Options (getopt_long)\n");
    printf("  8.  File Statistics (wc-like)\n");
    printf("  9.  Environment Config\n");
    printf("  10. Subcommand Parser\n");
    printf("\n");
    
#ifdef SHOW_ANSWERS
    printf("  (Answers are available - compile 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]);
    }
    
    /* Sample arguments for testing */
    char *sample_args[] = {
        "./exercise", "hello", "world", "123", "verylongargument",
        "-v", "-n", "42", "-o", "output.txt", NULL
    };
    int sample_argc = 10;
    
    switch (choice) {
        case 1:
            exercise1_argument_echo(sample_argc, sample_args);
#ifdef SHOW_ANSWERS
            answer1_argument_echo(sample_argc, sample_args);
#endif
            break;
            
        case 2:
            exercise2_reverse_arguments(sample_argc, sample_args);
#ifdef SHOW_ANSWERS
            answer2_reverse_arguments(sample_argc, sample_args);
#endif
            break;
            
        case 3:
            exercise3_sum_numbers(5, (char*[]){"prog", "10", "20", "30", "abc", NULL});
#ifdef SHOW_ANSWERS
            answer3_sum_numbers(5, (char*[]){"prog", "10", "20", "30", "abc", NULL});
#endif
            break;
            
        case 4:
            exercise4_longest_argument(sample_argc, sample_args);
#ifdef SHOW_ANSWERS
            answer4_longest_argument(sample_argc, sample_args);
#endif
            break;
            
        case 5:
            printf("Exercise 5 requires actual files.\n");
            printf("Usage: ./exercises 5 <pattern> <file1> [file2]...\n\n");
            if (argc > 3) {
                exercise5_simple_grep(argc - 1, argv + 1);
#ifdef SHOW_ANSWERS
                answer5_simple_grep(argc - 1, argv + 1);
#endif
            }
            break;
            
        case 6:
            exercise6_option_parser(sample_argc, sample_args);
#ifdef SHOW_ANSWERS
            answer6_option_parser(sample_argc, sample_args);
#endif
            break;
            
        case 7:
            exercise7_long_options(7, (char*[]){"prog", "--verbose", 
                "--number", "42", "--output", "file.txt", NULL});
#ifdef SHOW_ANSWERS
            answer7_long_options(7, (char*[]){"prog", "--verbose",
                "--number", "42", "--output", "file.txt", NULL});
#endif
            break;
            
        case 8:
            printf("Exercise 8 requires files or stdin.\n");
            printf("Usage: ./exercises 8 [-l] [-w] [-c] [file...]\n\n");
#ifdef SHOW_ANSWERS
            answer8_file_stats(3, (char*[]){"wc", "-l", "exercises.c", NULL});
#endif
            break;
            
        case 9:
            exercise9_env_config(3, (char*[]){"prog", "-d", "-o", "out.txt", NULL});
#ifdef SHOW_ANSWERS
            answer9_env_config(4, (char*[]){"prog", "-d", "-o", "out.txt", NULL});
#endif
            break;
            
        case 10:
            exercise10_subcommands(3, (char*[]){"prog", "list", "-a", NULL});
#ifdef SHOW_ANSWERS
            answer10_subcommands(3, (char*[]){"prog", "list", "-a", NULL});
#endif
            break;
            
        default:
            printf("Invalid choice. Run without arguments to see menu.\n");
            return 1;
    }
    
    return 0;
}
Exercises - C Programming Tutorial | DeepML