Virtual assistance

C Programming Tutorial

Welcome to AIVista --India's tutorial pages on C Programming

C Programming

Command Line Arguments in C

Command line arguments allow programs to accept input parameters when executed from the terminal or command prompt.

"Command line arguments in C are parameters passed to a program when it is executed from the command line, accessible through argc and argv in the main function."

What are Command Line Arguments?

Command line arguments are values passed to a program when it is executed from the command line. These arguments allow users to provide input to the program without interactive prompts.

Basic Syntax

program_name argument1 argument2 argument3 ...

Example Command Line Execution

./myprogram file.txt 42 "Hello World"
gcc -o output source.c -Wall -O2

main() Function Parameters

The main function can accept two optional parameters: argc and argv.

Parameter Definitions

  • argc (argument count): Integer representing the number of command line arguments
  • argv (argument vector): Array of strings containing the actual arguments

main() Function Signatures

// Standard main function
int main(void) {
    // No command line arguments
    return 0;
}

// Main function with command line arguments
int main(int argc, char *argv[]) {
    // argc - number of arguments
    // argv - array of argument strings
    return 0;
}

// Alternative syntax (equivalent)
int main(int argc, char **argv) {
    // Same as above
    return 0;
}

Understanding argc and argv

Basic Example

#include <stdio.h>

int main(int argc, char *argv[]) {
    printf("Number of arguments: %d\n", argc);

    printf("Program name: %s\n", argv[0]);

    for (int i = 1; i < argc; i++) {
        printf("Argument %d: %s\n", i, argv[i]);
    }

    return 0;
}

Sample Execution

$ ./program hello world 123
Number of arguments: 4
Program name: ./program
Argument 1: hello
Argument 2: world
Argument 3: 123

Argument Processing

Converting Arguments to Numbers

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

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("Usage: %s <num1> <num2>\n", argv[0]);
        return 1;
    }

    // Convert string arguments to integers
    int num1 = atoi(argv[1]);
    int num2 = atoi(argv[2]);

    printf("Sum: %d + %d = %d\n", num1, num2, num1 + num2);

    return 0;
}

Using strtol() for Better Error Handling

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Usage: %s <number>\n", argv[0]);
        return 1;
    }

    char *endptr;
    errno = 0;

    // Convert string to long integer
    long num = strtol(argv[1], &endptr, 10);

    // Check for conversion errors
    if (errno != 0 || *endptr != '\0') {
        printf("Error: Invalid number '%s'\n", argv[1]);
        return 1;
    }

    printf("Converted number: %ld\n", num);
    return 0;
}

Command Line Options and Flags

Simple Flag Processing

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

int main(int argc, char *argv[]) {
    int verbose = 0;
    char *filename = NULL;

    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) {
            verbose = 1;
        } else if (strcmp(argv[i], "-f") == 0 && i + 1 < argc) {
            filename = argv[i + 1];
            i++; // Skip next argument
        } else {
            printf("Unknown option: %s\n", argv[i]);
            return 1;
        }
    }

    if (verbose) {
        printf("Verbose mode enabled\n");
    }

    if (filename) {
        printf("Processing file: %s\n", filename);
    }

    return 0;
}

Advanced Option Parsing

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

#define MAX_FILES 10

typedef struct {
    int verbose;
    int help;
    char *output_file;
    char *input_files[MAX_FILES];
    int file_count;
} Options;

void print_help(char *program_name) {
    printf("Usage: %s [options] file1 [file2 ...]\n", program_name);
    printf("Options:\n");
    printf("  -v, --verbose    Enable verbose output\n");
    printf("  -o, --output FILE Specify output file\n");
    printf("  -h, --help       Show this help message\n");
}

Options parse_arguments(int argc, char *argv[]) {
    Options opts = {0, 0, NULL, {NULL}, 0};

    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) {
            opts.verbose = 1;
        } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
            opts.help = 1;
        } else if ((strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--output") == 0) && i + 1 < argc) {
            opts.output_file = argv[i + 1];
            i++;
        } else if (argv[i][0] != '-') {
            // Assume it's a filename
            if (opts.file_count < MAX_FILES) {
                opts.input_files[opts.file_count++] = argv[i];
            }
        } else {
            printf("Unknown option: %s\n", argv[i]);
            opts.help = 1;
        }
    }

    return opts;
}

int main(int argc, char *argv[]) {
    Options opts = parse_arguments(argc, argv);

    if (opts.help || argc == 1) {
        print_help(argv[0]);
        return 0;
    }

    if (opts.verbose) {
        printf("Verbose mode enabled\n");
    }

    if (opts.output_file) {
        printf("Output file: %s\n", opts.output_file);
    }

    printf("Input files:\n");
    for (int i = 0; i < opts.file_count; i++) {
        printf("  %s\n", opts.input_files[i]);
    }

    return 0;
}

Environment Variables

Programs can also access environment variables using the third parameter to main().

Accessing Environment Variables

#include <stdio.h>

int main(int argc, char *argv[], char *envp[]) {
    printf("Command line arguments:\n");
    for (int i = 0; i < argc; i++) {
        printf("  argv[%d]: %s\n", i, argv[i]);
    }

    printf("\nEnvironment variables:\n");
    for (int i = 0; envp[i] != NULL; i++) {
        printf("  %s\n", envp[i]);
    }

    return 0;
}

Using getenv() Function

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

int main(int argc, char *argv[]) {
    // Access specific environment variables
    char *home = getenv("HOME");
    char *path = getenv("PATH");
    char *user = getenv("USER");

    if (home) printf("Home directory: %s\n", home);
    if (path) printf("PATH: %.50s...\n", path); // Truncate for display
    if (user) printf("User: %s\n", user);

    return 0;
}

Practical Examples

1. File Copy Program with Command Line Arguments

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

#define BUFFER_SIZE 1024

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("Usage: %s <source_file> <destination_file>\n", argv[0]);
        return 1;
    }

    FILE *source = fopen(argv[1], "rb");
    if (source == NULL) {
        printf("Error: Cannot open source file '%s'\n", argv[1]);
        return 1;
    }

    FILE *dest = fopen(argv[2], "wb");
    if (dest == NULL) {
        printf("Error: Cannot create destination file '%s'\n", argv[2]);
        fclose(source);
        return 1;
    }

    char buffer[BUFFER_SIZE];
    size_t bytes_read;

    while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, source)) > 0) {
        fwrite(buffer, 1, bytes_read, dest);
    }

    fclose(source);
    fclose(dest);

    printf("File copied successfully from '%s' to '%s'\n", argv[1], argv[2]);

    return 0;
}

2. Simple Calculator

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

int main(int argc, char *argv[]) {
    if (argc != 4) {
        printf("Usage: %s <num1> <operator> <num2>\n", argv[0]);
        printf("Operators: +, -, *, /\n");
        return 1;
    }

    double num1 = atof(argv[1]);
    double num2 = atof(argv[3]);
    char operator = argv[2][0];
    double result;

    switch (operator) {
        case '+':
            result = num1 + num2;
            break;
        case '-':
            result = num1 - num2;
            break;
        case '*':
            result = num1 * num2;
            break;
        case '/':
            if (num2 == 0) {
                printf("Error: Division by zero\n");
                return 1;
            }
            result = num1 / num2;
            break;
        default:
            printf("Error: Unknown operator '%c'\n", operator);
            return 1;
    }

    printf("%.2f %c %.2f = %.2f\n", num1, operator, num2, result);

    return 0;
}

3. Text File Processor

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

#define MAX_LINE_LENGTH 1024

void process_file(FILE *file, int count_lines, int count_words, int count_chars, int to_upper) {
    char line[MAX_LINE_LENGTH];
    int lines = 0, words = 0, chars = 0;

    while (fgets(line, sizeof(line), file)) {
        lines++;

        if (to_upper) {
            for (int i = 0; line[i]; i++) {
                line[i] = toupper(line[i]);
            }
            printf("%s", line);
        }

        // Count characters
        chars += strlen(line);

        // Count words
        char *token = strtok(line, " \t\n");
        while (token != NULL) {
            words++;
            token = strtok(NULL, " \t\n");
        }
    }

    if (count_lines) printf("Lines: %d\n", lines);
    if (count_words) printf("Words: %d\n", words);
    if (count_chars) printf("Characters: %d\n", chars);
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        printf("Usage: %s [options] <filename>\n", argv[0]);
        printf("Options:\n");
        printf("  -l    Count lines\n");
        printf("  -w    Count words\n");
        printf("  -c    Count characters\n");
        printf("  -u    Convert to uppercase\n");
        return 1;
    }

    int count_lines = 0, count_words = 0, count_chars = 0, to_upper = 0;
    char *filename = NULL;

    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-l") == 0) count_lines = 1;
        else if (strcmp(argv[i], "-w") == 0) count_words = 1;
        else if (strcmp(argv[i], "-c") == 0) count_chars = 1;
        else if (strcmp(argv[i], "-u") == 0) to_upper = 1;
        else if (filename == NULL) filename = argv[i];
        else {
            printf("Error: Multiple filenames specified\n");
            return 1;
        }
    }

    if (filename == NULL) {
        printf("Error: No filename specified\n");
        return 1;
    }

    FILE *file = fopen(filename, "r");
    if (file == NULL) {
        printf("Error: Cannot open file '%s'\n", filename);
        return 1;
    }

    process_file(file, count_lines, count_words, count_chars, to_upper);

    fclose(file);
    return 0;
}

Best Practices for Command Line Arguments

  • Always validate the number of arguments
  • Provide clear usage messages
  • Use consistent option formats (-v, --verbose)
  • Handle errors gracefully
  • Allow both short and long option names
  • Validate argument types and ranges
  • Provide help option (-h, --help)

Common Issues and Solutions

1. Argument Parsing

// Problem: No validation
int num = atoi(argv[1]); // Crashes if argv[1] is NULL

// Solution: Check bounds and validate
if (argc < 2) {
    printf("Error: Missing argument\n");
    return 1;
}
char *endptr;
int num = strtol(argv[1], &endptr, 10);
if (*endptr != '\0') {
    printf("Error: Invalid number\n");
    return 1;
}

2. String Arguments with Spaces

// Command line: ./program "hello world" 123
// argv[1] = "hello world" (single argument)
// argv[2] = "123"

3. Program Name Variations

// Different program names based on execution
// ./myprogram -> argv[0] = "./myprogram"
// /usr/bin/myprogram -> argv[0] = "/usr/bin/myprogram"
// myprogram -> argv[0] = "myprogram"

Conclusion

Command line arguments provide a powerful way to make programs flexible and user-friendly. Understanding argc and argv allows you to create programs that can be easily integrated into scripts and automation workflows. Practice creating programs with various command line options to master this essential C programming skill! 🚀