google-site-verification: google61fe8ba583a51912.html
Command Line Parsing in C: Complete Guide

Introduction to Command Line Parsing

Command line argument parsing is essential for creating flexible and user-friendly C programs. Understanding how to process arguments passed to your program allows users to customize behavior, specify input/output files, and control program options.


Command Line Arguments Architecture

Program Execution: $ ./program arg1 arg2 arg3 Memory Layout: ┌─────────────────────┐ │ argv[0] = "./program"│ ├─────────────────────┤ │ argv[1] = "arg1" │ ├─────────────────────┤ │ argv[2] = "arg2" │ ├─────────────────────┤ │ argv[3] = "arg3" │ ├─────────────────────┤ │ argv[4] = NULL │ └─────────────────────┘ argc = 4 (number of arguments)

Basic Command Line Parsing

1. Simple Argument Access

#include <stdio.h> int main(int argc, char *argv[]) { printf("Number of arguments: %d\n", argc); printf("Program name: %s\n", argv[0]); if (argc > 1) { printf("Arguments:\n"); for (int i = 1; i < argc; i++) { printf(" argv[%d] = %s\n", i, argv[i]); } } else { printf("No additional arguments provided.\n"); } return 0; }

Compile and run:

$ gcc args.c -o args $ ./args hello world 123 Number of arguments: 4 Program name: ./args Arguments: argv[1] = hello argv[2] = world argv[3] = 123

2. Using Pointer Arithmetic

#include <stdio.h> int main(int argc, char **argv) { printf("Arguments using pointer arithmetic:\n"); // argv is a pointer to an array of strings for (int i = 0; i < argc; i++) { printf(" argv[%d] = %s (at address %p)\n", i, *(argv + i), (void*)*(argv + i)); } // Alternative: using pointer directly printf("\nUsing pointer directly:\n"); char **ptr = argv; int count = 0; while (*ptr != NULL) { printf(" Argument %d: %s\n", count++, *ptr); ptr++; } return 0; }

Simple Option Parsing

3. Basic Flag Parsing

#include <stdio.h> #include <string.h> #include <stdbool.h> typedef struct { bool verbose; bool help; int count; char *input_file; char *output_file; } Options; int main(int argc, char *argv[]) { Options opts = {false, false, 0, NULL, NULL}; // Parse arguments for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) { opts.verbose = true; } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { opts.help = true; } else if (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--count") == 0) { if (i + 1 < argc) { opts.count = atoi(argv[++i]); } else { printf("Error: --count requires a value\n"); return 1; } } else if (strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--input") == 0) { if (i + 1 < argc) { opts.input_file = argv[++i]; } else { printf("Error: --input requires a filename\n"); return 1; } } else if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--output") == 0) { if (i + 1 < argc) { opts.output_file = argv[++i]; } else { printf("Error: --output requires a filename\n"); return 1; } } else if (strcmp(argv[i], "--") == 0) { // Stop processing options break; } else if (argv[i][0] == '-') { printf("Unknown option: %s\n", argv[i]); return 1; } else { printf("Unexpected argument: %s\n", argv[i]); return 1; } } // Display parsed options printf("Parsed options:\n"); printf(" Verbose: %s\n", opts.verbose ? "yes" : "no"); printf(" Help: %s\n", opts.help ? "yes" : "no"); printf(" Count: %d\n", opts.count); printf(" Input file: %s\n", opts.input_file ? opts.input_file : "(none)"); printf(" Output file: %s\n", opts.output_file ? opts.output_file : "(none)"); return 0; }

Advanced Parsing with getopt

4. Using getopt() (POSIX)

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <getopt.h> #include <stdbool.h> typedef struct { int verbose; int count; char *input_file; char *output_file; int mode; double threshold; bool recursive; char **remaining_args; int remaining_count; } ProgramOptions; void print_usage(char *program_name) { printf("Usage: %s [options] [files...]\n", program_name); printf("Options:\n"); printf(" -v, --verbose Increase verbosity\n"); printf(" -c, --count NUM Set count value\n"); printf(" -i, --input FILE Input file\n"); printf(" -o, --output FILE Output file\n"); printf(" -m, --mode MODE Set mode (0-2)\n"); printf(" -t, --threshold VAL Set threshold (float)\n"); printf(" -r, --recursive Enable recursive processing\n"); printf(" -h, --help Show this help\n"); } int main(int argc, char *argv[]) { ProgramOptions opts = {0}; int opt; // Long options structure static struct option long_options[] = { {"verbose", no_argument, 0, 'v'}, {"count", required_argument, 0, 'c'}, {"input", required_argument, 0, 'i'}, {"output", required_argument, 0, 'o'}, {"mode", required_argument, 0, 'm'}, {"threshold", required_argument, 0, 't'}, {"recursive", no_argument, 0, 'r'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; // Parse options while ((opt = getopt_long(argc, argv, "vc:i:o:m:t:rh", long_options, NULL)) != -1) { switch (opt) { case 'v': opts.verbose++; break; case 'c': opts.count = atoi(optarg); break; case 'i': opts.input_file = optarg; break; case 'o': opts.output_file = optarg; break; case 'm': opts.mode = atoi(optarg); if (opts.mode < 0 || opts.mode > 2) { fprintf(stderr, "Mode must be 0, 1, or 2\n"); return 1; } break; case 't': opts.threshold = atof(optarg); break; case 'r': opts.recursive = true; break; case 'h': print_usage(argv[0]); return 0; case '?': // getopt already printed an error message return 1; default: fprintf(stderr, "Unexpected option: %c\n", opt); return 1; } } // Remaining arguments (non-option) opts.remaining_args = &argv[optind]; opts.remaining_count = argc - optind; // Display parsed options printf("=== Parsed Options ===\n"); printf("Verbosity level: %d\n", opts.verbose); printf("Count: %d\n", opts.count); printf("Input file: %s\n", opts.input_file ? opts.input_file : "(none)"); printf("Output file: %s\n", opts.output_file ? opts.output_file : "(none)"); printf("Mode: %d\n", opts.mode); printf("Threshold: %.2f\n", opts.threshold); printf("Recursive: %s\n", opts.recursive ? "yes" : "no"); printf("\n=== Remaining Arguments ===\n"); printf("Number of remaining args: %d\n", opts.remaining_count); for (int i = 0; i < opts.remaining_count; i++) { printf(" arg[%d]: %s\n", i, opts.remaining_args[i]); } return 0; }

Usage examples:

$ ./program -v -c 10 -i input.txt -o output.txt file1 file2 $ ./program --verbose --count=10 --input=input.txt file1 file2 $ ./program -v -m 2 -t 3.14 --recursive

Advanced getopt Examples

5. Complex getopt with Multiple Argument Types

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <getopt.h> #include <string.h> #include <ctype.h> #include <errno.h> typedef struct { char *config_file; char *log_file; int port; int threads; int timeout; char *hostname; int debug_level; int daemonize; char **include_paths; int include_count; char **exclude_patterns; int exclude_count; } ServerConfig; void print_config(ServerConfig *cfg) { printf("Server Configuration:\n"); printf(" Config file: %s\n", cfg->config_file ? cfg->config_file : "(default)"); printf(" Log file: %s\n", cfg->log_file ? cfg->log_file : "(default)"); printf(" Port: %d\n", cfg->port); printf(" Threads: %d\n", cfg->threads); printf(" Timeout: %d seconds\n", cfg->timeout); printf(" Hostname: %s\n", cfg->hostname ? cfg->hostname : "(default)"); printf(" Debug level: %d\n", cfg->debug_level); printf(" Daemonize: %s\n", cfg->daemonize ? "yes" : "no"); if (cfg->include_count > 0) { printf(" Include paths:\n"); for (int i = 0; i < cfg->include_count; i++) { printf(" %s\n", cfg->include_paths[i]); } } if (cfg->exclude_count > 0) { printf(" Exclude patterns:\n"); for (int i = 0; i < cfg->exclude_count; i++) { printf(" %s\n", cfg->exclude_patterns[i]); } } } // Function to parse integer with validation int parse_int(const char *str, int min, int max, const char *name) { char *endptr; errno = 0; long val = strtol(str, &endptr, 10); if (errno != 0 || *endptr != '\0' || val < min || val > max) { fprintf(stderr, "Invalid %s: must be integer between %d and %d\n", name, min, max); exit(1); } return (int)val; } int main(int argc, char *argv[]) { ServerConfig cfg = { .config_file = NULL, .log_file = NULL, .port = 8080, // default .threads = 4, // default .timeout = 30, // default .hostname = NULL, .debug_level = 0, .daemonize = 0, .include_paths = NULL, .include_count = 0, .exclude_patterns = NULL, .exclude_count = 0 }; // Temporary storage for multi-value options char *includes[100]; char *excludes[100]; static struct option long_options[] = { {"config", required_argument, 0, 'c'}, {"log", required_argument, 0, 'l'}, {"port", required_argument, 0, 'p'}, {"threads", required_argument, 0, 't'}, {"timeout", required_argument, 0, 'T'}, {"host", required_argument, 0, 'H'}, {"debug", required_argument, 0, 'd'}, {"daemon", no_argument, 0, 'D'}, {"include", required_argument, 0, 'I'}, {"exclude", required_argument, 0, 'X'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; int opt; int option_index = 0; while ((opt = getopt_long(argc, argv, "c:l:p:t:T:H:d:DI:X:h", long_options, &option_index)) != -1) { switch (opt) { case 'c': cfg.config_file = optarg; break; case 'l': cfg.log_file = optarg; break; case 'p': cfg.port = parse_int(optarg, 1, 65535, "port"); break; case 't': cfg.threads = parse_int(optarg, 1, 1000, "threads"); break; case 'T': cfg.timeout = parse_int(optarg, 1, 3600, "timeout"); break; case 'H': cfg.hostname = optarg; break; case 'd': cfg.debug_level = parse_int(optarg, 0, 3, "debug level"); break; case 'D': cfg.daemonize = 1; break; case 'I': if (cfg.include_count < 100) { includes[cfg.include_count++] = optarg; } break; case 'X': if (cfg.exclude_count < 100) { excludes[cfg.exclude_count++] = optarg; } break; case 'h': printf("Usage: %s [options]\n", argv[0]); printf("Options:\n"); printf(" -c, --config FILE Configuration file\n"); printf(" -l, --log FILE Log file\n"); printf(" -p, --port PORT Port number (1-65535)\n"); printf(" -t, --threads NUM Number of threads\n"); printf(" -T, --timeout SEC Timeout in seconds\n"); printf(" -H, --host HOST Hostname\n"); printf(" -d, --debug LEVEL Debug level (0-3)\n"); printf(" -D, --daemon Run as daemon\n"); printf(" -I, --include PATH Include path (can be repeated)\n"); printf(" -X, --exclude PATTERN Exclude pattern (can be repeated)\n"); printf(" -h, --help Show this help\n"); return 0; case '?': return 1; } } // Copy collected arrays to config if (cfg.include_count > 0) { cfg.include_paths = includes; } if (cfg.exclude_count > 0) { cfg.exclude_patterns = excludes; } print_config(&cfg); return 0; }

Manual Parsing Techniques

6. Manual Option Parsing

#include <stdio.h> #include <string.h> #include <stdlib.h> #include <stdbool.h> typedef struct { bool verbose; bool quiet; int level; char *input; char *output; int width; int height; char *format; bool overwrite; } ImageOptions; // Helper function to check if string starts with prefix bool starts_with(const char *str, const char *prefix) { return strncmp(str, prefix, strlen(prefix)) == 0; } // Helper function to parse key=value pairs bool parse_key_value(const char *arg, char **key, char **value) { char *equals = strchr(arg, '='); if (!equals) return false; size_t key_len = equals - arg; *key = malloc(key_len + 1); strncpy(*key, arg, key_len); (*key)[key_len] = '\0'; *value = strdup(equals + 1); return true; } int main(int argc, char *argv[]) { ImageOptions opts = { .verbose = false, .quiet = false, .level = 5, .input = NULL, .output = NULL, .width = 800, .height = 600, .format = "png", .overwrite = false }; // Manual parsing for (int i = 1; i < argc; i++) { char *arg = argv[i]; // Boolean flags if (strcmp(arg, "-v") == 0 || strcmp(arg, "--verbose") == 0) { opts.verbose = true; } else if (strcmp(arg, "-q") == 0 || strcmp(arg, "--quiet") == 0) { opts.quiet = true; } else if (strcmp(arg, "-f") == 0 || strcmp(arg, "--force") == 0) { opts.overwrite = true; } // Options with arguments else if (strcmp(arg, "-l") == 0 || strcmp(arg, "--level") == 0) { if (i + 1 < argc) { opts.level = atoi(argv[++i]); } else { fprintf(stderr, "Error: --level requires a value\n"); return 1; } } else if (strcmp(arg, "-i") == 0 || strcmp(arg, "--input") == 0) { if (i + 1 < argc) { opts.input = argv[++i]; } else { fprintf(stderr, "Error: --input requires a filename\n"); return 1; } } else if (strcmp(arg, "-o") == 0 || strcmp(arg, "--output") == 0) { if (i + 1 < argc) { opts.output = argv[++i]; } else { fprintf(stderr, "Error: --output requires a filename\n"); return 1; } } else if (strcmp(arg, "--size") == 0) { if (i + 2 < argc) { opts.width = atoi(argv[++i]); opts.height = atoi(argv[++i]); } else { fprintf(stderr, "Error: --size requires width and height\n"); return 1; } } // Key=value format else if (starts_with(arg, "--format=")) { opts.format = strchr(arg, '=') + 1; } else if (starts_with(arg, "--width=")) { opts.width = atoi(strchr(arg, '=') + 1); } else if (starts_with(arg, "--height=")) { opts.height = atoi(strchr(arg, '=') + 1); } // Unknown option else if (arg[0] == '-') { fprintf(stderr, "Unknown option: %s\n", arg); return 1; } // Positional arguments else { printf("Positional argument: %s\n", arg); } } // Display configuration printf("Image Options:\n"); printf(" Verbose: %s\n", opts.verbose ? "yes" : "no"); printf(" Quiet: %s\n", opts.quiet ? "yes" : "no"); printf(" Level: %d\n", opts.level); printf(" Input: %s\n", opts.input ? opts.input : "(none)"); printf(" Output: %s\n", opts.output ? opts.output : "(none)"); printf(" Size: %d x %d\n", opts.width, opts.height); printf(" Format: %s\n", opts.format); printf(" Overwrite: %s\n", opts.overwrite ? "yes" : "no"); return 0; }

Using argp (GNU argp parser)

7. GNU argp Parser

#include <stdio.h> #include <stdlib.h> #include <argp.h> const char *argp_program_version = "program 1.0"; const char *argp_program_bug_address = "<[email protected]>"; /* Program documentation. */ static char doc[] = "Program to demonstrate GNU argp parsing"; /* A description of the arguments we accept. */ static char args_doc[] = "INPUT_FILE OUTPUT_FILE"; /* The options we understand. */ static struct argp_option options[] = { {"verbose", 'v', 0, 0, "Produce verbose output"}, {"quiet", 'q', 0, 0, "Don't produce any output"}, {"silent", 's', 0, OPTION_ALIAS}, {"output", 'o', "FILE", 0, "Output to FILE instead of standard output"}, {"count", 'c', "NUM", 0, "Process NUM times"}, {"mode", 'm', "MODE", 0, "Processing mode (0,1,2)"}, {0} }; /* Used by main to communicate with parse_opt. */ struct arguments { char *args[2]; /* INPUT_FILE, OUTPUT_FILE */ int silent, verbose; char *output_file; int count; int mode; }; /* Parse a single option. */ static error_t parse_opt(int key, char *arg, struct argp_state *state) { struct arguments *arguments = state->input; switch (key) { case 'v': arguments->verbose = 1; break; case 'q': case 's': arguments->silent = 1; break; case 'o': arguments->output_file = arg; break; case 'c': arguments->count = atoi(arg); break; case 'm': arguments->mode = atoi(arg); break; case ARGP_KEY_ARG: if (state->arg_num >= 2) { /* Too many arguments. */ argp_usage(state); } arguments->args[state->arg_num] = arg; break; case ARGP_KEY_END: if (state->arg_num < 2) { /* Not enough arguments. */ argp_usage(state); } break; default: return ARGP_ERR_UNKNOWN; } return 0; } /* Our argp parser. */ static struct argp argp = {options, parse_opt, args_doc, doc}; int main(int argc, char *argv[]) { struct arguments arguments; /* Default values. */ arguments.silent = 0; arguments.verbose = 0; arguments.output_file = "-"; arguments.count = 1; arguments.mode = 0; /* Parse our arguments. */ argp_parse(&argp, argc, argv, 0, 0, &arguments); /* Display results. */ printf("INPUT_FILE = %s\n", arguments.args[0]); printf("OUTPUT_FILE = %s\n", arguments.args[1]); printf("VERBOSE = %s\n", arguments.verbose ? "yes" : "no"); printf("SILENT = %s\n", arguments.silent ? "yes" : "no"); printf("OUTPUT_FILE = %s\n", arguments.output_file); printf("COUNT = %d\n", arguments.count); printf("MODE = %d\n", arguments.mode); return 0; }

Compile and run:

$ gcc -o argp_example argp_example.c $ ./argp_example -v -c 5 -m 2 input.txt output.txt

Subcommand Parsing

8. Git-style Subcommands

#include <stdio.h> #include <string.h> #include <stdlib.h> typedef struct { char *command; int argc; char **argv; } Subcommand; // Subcommand handlers int cmd_add(int argc, char *argv[]) { printf("Executing 'add' command\n"); for (int i = 0; i < argc; i++) { printf(" add arg[%d]: %s\n", i, argv[i]); } return 0; } int cmd_commit(int argc, char *argv[]) { char *message = NULL; int amend = 0; printf("Executing 'commit' command\n"); for (int i = 0; i < argc; i++) { if (strcmp(argv[i], "-m") == 0 && i + 1 < argc) { message = argv[++i]; } else if (strcmp(argv[i], "--amend") == 0) { amend = 1; } else { printf(" Unknown commit option: %s\n", argv[i]); } } if (message) { printf(" Message: %s\n", message); } printf(" Amend: %s\n", amend ? "yes" : "no"); return 0; } int cmd_push(int argc, char *argv[]) { char *remote = NULL; char *branch = NULL; int force = 0; printf("Executing 'push' command\n"); for (int i = 0; i < argc; i++) { if (strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "--force") == 0) { force = 1; } else if (remote == NULL) { remote = argv[i]; } else if (branch == NULL) { branch = argv[i]; } } printf(" Remote: %s\n", remote ? remote : "(default)"); printf(" Branch: %s\n", branch ? branch : "(default)"); printf(" Force: %s\n", force ? "yes" : "no"); return 0; } int cmd_status(int argc, char *argv[]) { int short_format = 0; int branch_info = 0; printf("Executing 'status' command\n"); for (int i = 0; i < argc; i++) { if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--short") == 0) { short_format = 1; } else if (strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "--branch") == 0) { branch_info = 1; } } printf(" Short format: %s\n", short_format ? "yes" : "no"); printf(" Branch info: %s\n", branch_info ? "yes" : "no"); return 0; } void print_usage(char *progname) { printf("Usage: %s <command> [options]\n", progname); printf("\nCommands:\n"); printf(" add <files...> Add file contents to the index\n"); printf(" commit -m MSG Record changes to the repository\n"); printf(" push [remote] [branch] Update remote refs\n"); printf(" status Show the working tree status\n"); printf("\nGlobal options:\n"); printf(" -h, --help Show this help\n"); } int main(int argc, char *argv[]) { if (argc < 2) { print_usage(argv[0]); return 1; } // Check for global help if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) { print_usage(argv[0]); return 0; } // Parse command char *command = argv[1]; int cmd_argc = argc - 2; char **cmd_argv = (cmd_argc > 0) ? &argv[2] : NULL; // Execute command if (strcmp(command, "add") == 0) { return cmd_add(cmd_argc, cmd_argv); } else if (strcmp(command, "commit") == 0) { return cmd_commit(cmd_argc, cmd_argv); } else if (strcmp(command, "push") == 0) { return cmd_push(cmd_argc, cmd_argv); } else if (strcmp(command, "status") == 0) { return cmd_status(cmd_argc, cmd_argv); } else { fprintf(stderr, "Unknown command: %s\n", command); print_usage(argv[0]); return 1; } }

Usage examples:

$ ./git add file1.c file2.c $ ./git commit -m "Initial commit" $ ./git push origin main $ ./git status -s

Environment Variables

9. Environment Variable Parsing

#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char *home; char *user; char *path; int debug; int threads; char *config_dir; } EnvironmentConfig; // Get environment variable with default char* get_env_default(const char *name, const char *default_value) { char *value = getenv(name); return value ? value : (char*)default_value; } // Parse integer from environment int get_env_int(const char *name, int default_value) { char *value = getenv(name); if (value) { return atoi(value); } return default_value; } int main(int argc, char *argv[]) { EnvironmentConfig cfg; // Get standard environment variables cfg.home = get_env_default("HOME", "/tmp"); cfg.user = get_env_default("USER", "unknown"); cfg.path = get_env_default("PATH", ""); // Application-specific environment variables cfg.debug = get_env_int("MYAPP_DEBUG", 0); cfg.threads = get_env_int("MYAPP_THREADS", 4); cfg.config_dir = get_env_default("MYAPP_CONFIG", "/etc/myapp"); printf("=== Environment Configuration ===\n"); printf("HOME: %s\n", cfg.home); printf("USER: %s\n", cfg.user); printf("PATH: %s\n", cfg.path); printf("MYAPP_DEBUG: %d\n", cfg.debug); printf("MYAPP_THREADS: %d\n", cfg.threads); printf("MYAPP_CONFIG: %s\n", cfg.config_dir); // Override with command line arguments printf("\n=== Command Line Overrides ===\n"); for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "--debug") == 0 && i + 1 < argc) { cfg.debug = atoi(argv[++i]); printf("Debug overridden to: %d\n", cfg.debug); } else if (strcmp(argv[i], "--threads") == 0 && i + 1 < argc) { cfg.threads = atoi(argv[++i]); printf("Threads overridden to: %d\n", cfg.threads); } } return 0; }

Usage:

$ export MYAPP_DEBUG=1 $ export MYAPP_THREADS=8 $ ./program --debug 2 --threads 16

Configuration File Support

10. Combined Command Line and Config File

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #define MAX_LINE 256 typedef struct { char *server; int port; char *database; char *username; char *password; int max_connections; int timeout; int debug; } DatabaseConfig; // Trim whitespace from string char* trim(char *str) { char *end; // Trim leading space while (isspace((unsigned char)*str)) str++; if (*str == 0) return str; // Trim trailing space end = str + strlen(str) - 1; while (end > str && isspace((unsigned char)*end)) end--; // Write new null terminator *(end + 1) = '\0'; return str; } // Parse config file void parse_config_file(const char *filename, DatabaseConfig *cfg) { FILE *file = fopen(filename, "r"); if (!file) { printf("No config file found, using defaults\n"); return; } char line[MAX_LINE]; int line_num = 0; while (fgets(line, sizeof(line), file)) { line_num++; // Remove comments char *comment = strchr(line, '#'); if (comment) *comment = '\0'; // Trim whitespace char *trimmed = trim(line); if (strlen(trimmed) == 0) continue; // Split key=value char *equals = strchr(trimmed, '='); if (!equals) { printf("Warning: line %d: no '=' found\n", line_num); continue; } *equals = '\0'; char *key = trim(trimmed); char *value = trim(equals + 1); // Parse key-value pairs if (strcmp(key, "server") == 0) { cfg->server = strdup(value); } else if (strcmp(key, "port") == 0) { cfg->port = atoi(value); } else if (strcmp(key, "database") == 0) { cfg->database = strdup(value); } else if (strcmp(key, "username") == 0) { cfg->username = strdup(value); } else if (strcmp(key, "password") == 0) { cfg->password = strdup(value); } else if (strcmp(key, "max_connections") == 0) { cfg->max_connections = atoi(value); } else if (strcmp(key, "timeout") == 0) { cfg->timeout = atoi(value); } else if (strcmp(key, "debug") == 0) { cfg->debug = atoi(value); } } fclose(file); } // Parse command line arguments (overrides config file) void parse_command_line(int argc, char *argv[], DatabaseConfig *cfg) { for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--config") == 0) { if (i + 1 < argc) { parse_config_file(argv[++i], cfg); } } else if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--server") == 0) { if (i + 1 < argc) cfg->server = argv[++i]; } else if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--port") == 0) { if (i + 1 < argc) cfg->port = atoi(argv[++i]); } else if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--database") == 0) { if (i + 1 < argc) cfg->database = argv[++i]; } else if (strcmp(argv[i], "-u") == 0 || strcmp(argv[i], "--user") == 0) { if (i + 1 < argc) cfg->username = argv[++i]; } else if (strcmp(argv[i], "-P") == 0 || strcmp(argv[i], "--password") == 0) { if (i + 1 < argc) cfg->password = argv[++i]; } else if (strcmp(argv[i], "-m") == 0 || strcmp(argv[i], "--max-conn") == 0) { if (i + 1 < argc) cfg->max_connections = atoi(argv[++i]); } else if (strcmp(argv[i], "-t") == 0 || strcmp(argv[i], "--timeout") == 0) { if (i + 1 < argc) cfg->timeout = atoi(argv[++i]); } else if (strcmp(argv[i], "--debug") == 0) { cfg->debug = 1; } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { printf("Usage: %s [options]\n", argv[0]); printf("Options:\n"); printf(" -c, --config FILE Config file\n"); printf(" -s, --server HOST Database server\n"); printf(" -p, --port PORT Server port\n"); printf(" -d, --database DB Database name\n"); printf(" -u, --user USER Username\n"); printf(" -P, --password PASS Password\n"); printf(" -m, --max-conn NUM Max connections\n"); printf(" -t, --timeout SEC Timeout\n"); printf(" --debug Enable debug\n"); exit(0); } } } int main(int argc, char *argv[]) { DatabaseConfig cfg = { .server = "localhost", .port = 5432, .database = "mydb", .username = NULL, .password = NULL, .max_connections = 100, .timeout = 30, .debug = 0 }; // Parse command line (which may specify config file) parse_command_line(argc, argv, &cfg); // Display configuration printf("=== Database Configuration ===\n"); printf("Server: %s\n", cfg.server); printf("Port: %d\n", cfg.port); printf("Database: %s\n", cfg.database); printf("Username: %s\n", cfg.username ? cfg.username : "(none)"); printf("Password: %s\n", cfg.password ? "********" : "(none)"); printf("Max connections: %d\n", cfg.max_connections); printf("Timeout: %d seconds\n", cfg.timeout); printf("Debug: %s\n", cfg.debug ? "yes" : "no"); return 0; }

Example config file (database.conf):

# Database configuration server = db.example.com port = 3306 database = production_db username = app_user password = secret123 max_connections = 200 timeout = 60 debug = 1

Argument Validation and Error Handling

11. Robust Argument Validation

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <errno.h> typedef struct { char *input_file; char *output_file; int width; int height; int quality; char *format; int verbose; } ImageConfig; // Validate file extension int valid_extension(const char *filename, const char *ext) { const char *dot = strrchr(filename, '.'); return dot && strcasecmp(dot + 1, ext) == 0; } // Validate positive integer int validate_positive_int(const char *str, const char *name, int min, int max) { char *endptr; errno = 0; long val = strtol(str, &endptr, 10); if (errno != 0 || *endptr != '\0') { fprintf(stderr, "Error: %s must be an integer\n", name); exit(1); } if (val < min || val > max) { fprintf(stderr, "Error: %s must be between %d and %d\n", name, min, max); exit(1); } return (int)val; } // Validate format string int validate_format(const char *format) { static const char *valid_formats[] = {"png", "jpg", "jpeg", "bmp", "gif", "tiff"}; int num_formats = sizeof(valid_formats) / sizeof(valid_formats[0]); for (int i = 0; i < num_formats; i++) { if (strcasecmp(format, valid_formats[i]) == 0) { return 1; } } return 0; } // Validate input file exists int file_exists(const char *filename) { FILE *file = fopen(filename, "r"); if (file) { fclose(file); return 1; } return 0; } int main(int argc, char *argv[]) { ImageConfig cfg = { .input_file = NULL, .output_file = NULL, .width = 800, .height = 600, .quality = 90, .format = "png", .verbose = 0 }; // Parse arguments with validation for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--input") == 0) { if (i + 1 >= argc) { fprintf(stderr, "Error: --input requires a filename\n"); return 1; } cfg.input_file = argv[++i]; // Validate input file exists if (!file_exists(cfg.input_file)) { fprintf(stderr, "Error: input file '%s' does not exist\n", cfg.input_file); return 1; } } else if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--output") == 0) { if (i + 1 >= argc) { fprintf(stderr, "Error: --output requires a filename\n"); return 1; } cfg.output_file = argv[++i]; } else if (strcmp(argv[i], "--width") == 0) { if (i + 1 >= argc) { fprintf(stderr, "Error: --width requires a value\n"); return 1; } cfg.width = validate_positive_int(argv[++i], "width", 1, 10000); } else if (strcmp(argv[i], "--height") == 0) { if (i + 1 >= argc) { fprintf(stderr, "Error: --height requires a value\n"); return 1; } cfg.height = validate_positive_int(argv[++i], "height", 1, 10000); } else if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quality") == 0) { if (i + 1 >= argc) { fprintf(stderr, "Error: --quality requires a value\n"); return 1; } cfg.quality = validate_positive_int(argv[++i], "quality", 1, 100); } else if (strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "--format") == 0) { if (i + 1 >= argc) { fprintf(stderr, "Error: --format requires a value\n"); return 1; } cfg.format = argv[++i]; // Validate format if (!validate_format(cfg.format)) { fprintf(stderr, "Error: invalid format '%s'. Supported: png, jpg, bmp, gif, tiff\n", cfg.format); return 1; } } else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) { cfg.verbose = 1; } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { printf("Usage: %s [options]\n", argv[0]); printf("Options:\n"); printf(" -i, --input FILE Input image file (required)\n"); printf(" -o, --output FILE Output image file (required)\n"); printf(" --width WIDTH Output width (1-10000)\n"); printf(" --height HEIGHT Output height (1-10000)\n"); printf(" -q, --quality Q JPEG quality (1-100)\n"); printf(" -f, --format FMT Output format (png, jpg, bmp, gif, tiff)\n"); printf(" -v, --verbose Verbose output\n"); printf(" -h, --help Show this help\n"); return 0; } else { fprintf(stderr, "Unknown option: %s\n", argv[i]); return 1; } } // Validate required arguments if (!cfg.input_file) { fprintf(stderr, "Error: input file is required\n"); return 1; } if (!cfg.output_file) { fprintf(stderr, "Error: output file is required\n"); return 1; } // Validate output file extension matches format if (!valid_extension(cfg.output_file, cfg.format)) { fprintf(stderr, "Warning: output file extension does not match format '%s'\n", cfg.format); } // Display configuration printf("=== Image Processing Configuration ===\n"); printf("Input: %s\n", cfg.input_file); printf("Output: %s\n", cfg.output_file); printf("Size: %d x %d\n", cfg.width, cfg.height); printf("Quality: %d\n", cfg.quality); printf("Format: %s\n", cfg.format); printf("Verbose: %s\n", cfg.verbose ? "yes" : "no"); return 0; }

Summary Table

Parsing MethodProsConsBest For
Manual parsingSimple, no dependenciesError-prone, verboseSmall utilities
getopt()POSIX standard, reliableLimited to short optionsPortable programs
getopt_long()GNU style, long optionsGNU extensionMost Linux programs
argpVery powerful, built-in helpGNU specific, complexComplex GNU tools
SubcommandsGit-style interfaceMore complexMulti-purpose tools
Config filesPersistent settingsFile I/O overheadServer applications
Environment varsSystem-wide configHarder to discoverDaemon configuration

Best Practices Summary

Do's and Don'ts

// DO: Validate all user input if (argc < 2) { fprintf(stderr, "Usage: %s <filename>\n", argv[0]); return 1; } // DO: Use consistent option naming // Short: -v, -f, -o // Long: --verbose, --file, --output // DO: Provide meaningful help text void print_help() { printf("Usage: %s [OPTIONS] <file>\n", program_name); printf("Options:\n"); printf(" -v, --verbose Increase verbosity\n"); } // DO: Check for required arguments if (!input_file) { fprintf(stderr, "Error: input file required\n"); return 1; } // DON'T: Ignore unused arguments while ((opt = getopt(argc, argv, "vf:o:")) != -1) { // Handle all options } // DON'T: Use ambiguous option names // Bad: -a (what does it do?) // Good: -a, --append // DO: Handle the -- separator if (strcmp(argv[i], "--") == 0) { // Stop processing options i++; break; } // DO: Validate numeric ranges int port = atoi(optarg); if (port < 1 || port > 65535) { fprintf(stderr, "Invalid port number\n"); return 1; }

Common Patterns Summary

PatternCode ExampleUse Case
Boolean flagcase 'v': verbose = true; break;Enable/disable features
Value optioncase 'p': port = atoi(optarg); break;Numeric configuration
String optioncase 'f': filename = optarg; break;File names, hostnames
Multiple valuescase 'I': includes[count++] = optarg;Lists of items
Key=valueparse_key_value(arg, &key, &value);Complex parameters
Subcommandsif (strcmp(argv[1], "add") == 0)Multi-tool programs
Config fileparse_config_file("app.conf", &cfg);Persistent settings

Conclusion

Command line parsing is a fundamental skill for C programmers:

Key Takeaways

  1. argc/argv provide access to command line arguments
  2. getopt() and getopt_long() simplify option parsing
  3. argp offers advanced features for complex programs
  4. Manual parsing works for simple cases
  5. Subcommands create intuitive multi-tool interfaces
  6. Configuration files complement command line options
  7. Environment variables provide system-wide settings
  8. Validation is crucial for robust programs

Choosing the Right Approach

  • Simple scripts: Manual parsing or basic getopt
  • Standard Unix tools: getopt() for POSIX compliance
  • GNU/Linux programs: getopt_long() for long options
  • Complex tools: argp for built-in help and features
  • Git-like tools: Subcommand architecture
  • Servers/daemons: Config files + command line overrides

Mastering command line parsing enables you to create professional, user-friendly programs that follow established conventions and provide flexible configuration options.

Complete C Programming Guide + Compilers Collection


1. C srand() Function – Understanding Seed Initialization

https://macronepal.com/understanding-the-c-srand-function
Explains how srand() initializes the pseudo-random number generator in C by setting a seed value. Using the same seed produces the same sequence, while time(NULL) gives different results each run.


2. C rand() Function Mechanics and Limitations

https://macronepal.com/c-rand-function-mechanics-and-limitations
Explains how rand() generates pseudo-random numbers between 0 and RAND_MAX, its deterministic nature, and limitations for security use cases.


3. C log() Function

https://macronepal.com/c-log-function-2
Covers natural logarithm calculation using <math.h> and its applications.


4. Mastering Date and Time in C

https://macronepal.com/mastering-date-and-time-in-c
Explains <time.h> functions like time(), clock(), difftime(), and struct tm.


5. Mastering time_t Type in C

https://macronepal.com/mastering-the-c-time_t-type-for-time-management
Explains time representation as seconds since Unix epoch and conversion functions.


6. C exp() Function

https://macronepal.com/c-exp-function-mechanics-and-implementation
Explains exponential function exp(x) and its scientific applications.


7. C log() Function (Alternate Guide)

https://macronepal.com/c-log-function
Comparison of log() and log10() with usage examples.


8. C log10() Function

https://macronepal.com/mastering-the-log10-function-in-c
Explains base-10 logarithm for engineering and scientific applications.


9. C tan() Function

https://macronepal.com/understanding-the-c-tan-function
Explains tangent function and radian-based calculations.


10. Random Numbers in C (Secure vs Predictable)

https://macronepal.com/mastering-c-random-numbers-for-secure-and-predictable-applications
Explains difference between rand() and secure randomness methods.


11. Free Online C Compiler

https://macronepal.com/free-online-c-code-compiler-2
Browser-based compiler for testing C programs instantly.


C Functions, Arguments, Parameters & Flow

Mastering Functions in C – Complete Guide

https://macronepal.com/c/mastering-functions-in-c-a-complete-guide/
Covers function structure, modular programming, and real-world usage.


Function Arguments in C

https://macronepal.com/c-function-arguments/
Explains how arguments are passed and used in function calls.


Function Parameters in C

https://macronepal.com/c-function-parameters/
Explains defining inputs for functions and matching them with arguments.


Function Declarations in C

https://macronepal.com/c-function-declarations-syntax-rules-and-best-practices/
Covers prototypes, syntax rules, and best practices.


Function Calls in C

https://macronepal.com/understanding-function-calls-in-c-syntax-mechanics-and-best-practices/
Explains execution flow and parameter handling during function calls.


Void Functions in C

https://macronepal.com/understanding-void-functions-in-c-syntax-patterns-and-best-practices/
Explains functions that do not return values.


Return Values in C

https://macronepal.com/c-return-values-mechanics-types-and-best-practices/
Explains different return types and how functions return results.


Pass-by-Value in C

https://macronepal.com/aws/understanding-pass-by-value-in-c-mechanics-implications-and-best-practices/
Explains how copies of variables are passed into functions.


Pass-by-Reference in C

https://macronepal.com/c/understanding-pass-by-reference-in-c-pointers-semantics-and-safe-practices/
Explains using pointers to modify original variables.


C strstr() Function

https://macronepal.com/aws/c-strstr-function/
Explains substring search inside strings in C.


C Preprocessor & Macros

https://macronepal.com/mastering-c-variadic-macros-for-flexible-debugging/
https://macronepal.com/mastering-the-stdc-macro-in-c/
https://macronepal.com/c-time-macro-mechanics-and-usage/
https://macronepal.com/understanding-the-c-date-macro/
https://macronepal.com/c-file-type/
https://macronepal.com/mastering-c-line-macro-for-debugging-and-diagnostics/
https://macronepal.com/mastering-predefined-macros-in-c/
https://macronepal.com/c-error-directive-mechanics-and-usage/
https://macronepal.com/understanding-the-c-pragma-directive/
https://macronepal.com/c-include-directive/


C Structures, Memory, Scope & Linkage

https://macronepal.com/mastering-structures-in-c/
https://macronepal.com/c-structure-declaration-mechanics-and-usage/
https://macronepal.com/c-structure-initialization-mechanics-and-best-practices/
https://macronepal.com/mastering-c-structure-member-access-for-reliable-data-handling/
https://macronepal.com/c-nested-structures/
https://macronepal.com/mastering-arrays-of-structures-in-c/
https://macronepal.com/c-structure-pointers-mechanics-and-implementation/
https://macronepal.com/understanding-c-structure-parameter-passing-mechanics/
https://macronepal.com/mastering-c-returning-structures-for-efficient-data-flow/
https://macronepal.com/c-self-referential-structures/
https://macronepal.com/mastering-structure-alignment-in-c/
https://macronepal.com/c-structure-padding-mechanics-and-optimization/
https://macronepal.com/understanding-c-flexible-array-members-mechanics-and-usage/
https://macronepal.com/mastering-c-anonymous-structures-for-flattened-data-layouts/
https://macronepal.com/c-unions/
https://macronepal.com/mastering-c-name-mangling-and-symbol-decoration/
https://macronepal.com/c-no-linkage-mechanics-and-scope-isolation/
https://macronepal.com/understanding-c-internal-linkage-mechanics-and-architecture/


C Scope, Storage Classes & Typedef

https://macronepal.com/mastering-function-prototype-scope-in-c/
https://macronepal.com/c-function-scope-mechanics-and-visibility/
https://macronepal.com/understanding-c-file-scope-mechanics-and-architecture/
https://macronepal.com/mastering-c-scope-rules-for-predictable-name-resolution/
https://macronepal.com/c-scope-rules/
https://macronepal.com/mastering-c-register-storage-class-for-historical-context-and-modern-alternatives/
https://macronepal.com/mastering-_thread_local-in-c/
https://macronepal.com/c-extern-storage-class-mechanics-and-usage/
https://macronepal.com/understanding-the-c-static-storage-class-mechanics-and-usage/
https://macronepal.com/c-auto-storage-class/
https://macronepal.com/c-typedef-with-pointers/


Extra Articles

https://macronepal.com/13757-2/
https://macronepal.com/13748-2/
https://macronepal.com/13747-2/
https://macronepal.com/13746-2/
https://macronepal.com/13745-2/
https://macronepal.com/13708-2/
https://macronepal.com/13707-2/
https://macronepal.com/13702-2/


Online Compilers

https://macronepal.com/free-html-online-code-compiler/
https://macronepal.com/free-online-python-code-compiler/
https://macronepal.com/free-online-python2-code-compiler/
https://macronepal.com/free-online-java-code-compiler/
https://macronepal.com/free-online-javascript-code-compiler/
https://macronepal.com/free-online-node-js-code-compiler/
https://macronepal.com/free-online-c-code-compiler/
https://macronepal.com/free-online-c-code-compiler-2/
https://macronepal.com/free-online-c-code-compiler-3/
https://macronepal.com/free-online-php-code-compiler/
https://macronepal.com/free-online-ruby-code-compiler/
https://macronepal.com/free-online-perl-code-compiler/
https://macronepal.com/free-online-lua-code-compiler/
https://macronepal.com/free-online-tcl-code-compiler/
https://macronepal.com/free-online-groovy-code-compiler/
https://macronepal.com/free-online-j-shell-code-compiler/
https://macronepal.com/free-online-haskell-code-compiler/
https://macronepal.com/free-online-scala-code-compiler/
https://macronepal.com/free-online-common-lisp-code-compiler/
https://macronepal.com/free-online-d-code-compiler/
https://macronepal.com/free-online-ada-code-compiler/
https://macronepal.com/free-erlang-code-compiler/
https://macronepal.com/free-online-assembly-code-compiler/

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper