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! 🚀