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