Parsing Command-Line Arguments with argc and argv in C
Command-line arguments allow users to pass inputs directly into a C
program at the moment of execution, eliminating the need for interactive
prompts during runtime. In C, these arguments are received by the
main() function through two predefined parameters:
argc and argv. This article explains the
technical mechanics of argc and argv, how data
is structured in memory, and how to safely inspect, iterate over, and
convert command-line inputs into usable data types within your
programs.
The main() Function
Signature
To process command-line inputs, the entry-point function
main must be declared with parameters that accept input
metadata:
int main(int argc, char *argv[])Alternatively, you can write char **argv, which is
syntactically equivalent.
argc(Argument Count): An integer that stores the total number of command-line arguments passed to the program, including the program's invocation command itself. Its value is always at least1.argv(Argument Vector): An array of pointers to null-terminated character strings (char*). Each pointer in this array references an individual argument provided on the command line.
Structure of argc and
argv
When a program is executed from a shell—such as
./app file.txt 42—the operating system splits the input
string by whitespace, constructs an array of strings, and passes them to
the binary:
argcis set to3.argv[0]holds the string representation of how the program was invoked (e.g.,"./app").argv[1]contains"file.txt".argv[2]contains"42".argv[argc](in this caseargv[3]) is guaranteed by the C standard to be aNULLpointer, which marks the end of the array.
Basic Iteration and Reading
The most direct way to inspect command-line arguments is by looping
through the array using a standard for loop up to
argc:
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Total arguments: %d\n", argc);
for (int i = 0; i < argc; i++) {
printf("argv[%d]: %s\n", i, argv[i]);
}
return 0;
}Because argv[argc] is NULL, you can also
iterate using pointer arithmetic without relying on the index
counter:
char **ptr = argv;
while (*ptr != NULL) {
printf("%s\n", *ptr);
ptr++;
}Parsing and Type Conversion
Every argument stored in argv is represented as a
character array (string), regardless of what was typed in the terminal.
If an argument is intended to be a numerical value, it must be
explicitly converted using standard library functions like
atoi, strtol, or strtod found in
<stdlib.h>.
Using strtol is the recommended practice because it
provides error checking to verify whether the conversion succeeded:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: %s <number>\n", argv[0]);
return 1;
}
char *endptr;
long val = strtol(argv[1], &endptr, 10);
// Check if conversion succeeded
if (endptr == argv[1] || *endptr != '\0') {
fprintf(stderr, "Error: '%s' is not a valid integer.\n", argv[1]);
return 1;
}
printf("Parsed number: %ld\n", val);
return 0;
}Handling Flags and Options
Basic command-line flags (such as -v or
-f filename) are typically parsed by comparing strings
using strcmp from <string.h>:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int verbose = 0;
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], "-o") == 0) {
if (i + 1 < argc) {
printf("Output file: %s\n", argv[++i]);
} else {
fprintf(stderr, "Error: -o requires a filename.\n");
return 1;
}
}
}
if (verbose) {
printf("Verbose mode enabled.\n");
}
return 0;
}For complex CLI interfaces requiring support for short flags, long
options, and combined switches (such as -xzf), standard
POSIX libraries provide the getopt() and
getopt_long() functions, which automate tokenization and
state tracking while operating on top of the underlying
argc and argv structures.