Command-Line Arguments
Most real programs take their input from the command line: gcc main.c -o main, git commit -m "…". In C, main can receive those words through two parameters, argc and argv.
argc and argv
#include <stdio.h> int main(int argc, char *argv[]) { printf("argc = %d\n", argc); for (int i = 0; i < argc; i++) { printf("argv[%d] = \"%s\"\n", i, argv[i]); } return 0; }
argc = 4 argv[0] = "./prog" argv[1] = "report.csv" argv[2] = "--verbose" argv[3] = "42"
This was run as ./prog report.csv --verbose 42:
argcis the number of arguments, including the program's own name.argvis an array of strings;argv[0]is the program name (or path), andargv[argc]isNULL.- Every argument is a string, even
42— convert it yourself.
The shell splits arguments at spaces, so to pass text containing spaces, quote it: ./prog "hello world".
Converting and checking
#include <stdio.h> #include <stdlib.h> #include <errno.h> int parse_int(const char *text, long *out) { char *end; errno = 0; long value = strtol(text, &end, 10); if (end == text || *end != '\0' || errno == ERANGE) return 0; *out = value; return 1; } int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "usage: %s WIDTH HEIGHT\n", argv[0]); return 1; } long w, h; if (!parse_int(argv[1], &w) || !parse_int(argv[2], &h)) { fprintf(stderr, "WIDTH and HEIGHT must be whole numbers\n"); return 1; } printf("area: %ld\n", w * h); return 0; }
area: 360
Run as ./prog 12 30. A program should check how many arguments it got and print a usage message to stderr — and exit with a non-zero status — when they're wrong. Here it was run as ./prog 12:
#include <stdio.h> int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "usage: %s WIDTH HEIGHT\n", argv[0]); return 1; } return 0; }
usage: ./prog WIDTH HEIGHT
Options
Unix programs conventionally take options starting with -. A simple loop handles them:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> int main(int argc, char *argv[]) { int repeat = 1, upper = 0; int i = 1; for (; i < argc && argv[i][0] == '-'; i++) { if (strcmp(argv[i], "-u") == 0) { upper = 1; } else if (strcmp(argv[i], "-n") == 0 && i + 1 < argc) { repeat = atoi(argv[++i]); } else { fprintf(stderr, "unknown option %s\n", argv[i]); return 1; } } for (int r = 0; r < repeat; r++) { for (int j = i; j < argc; j++) { for (const char *p = argv[j]; *p; p++) { putchar(upper ? toupper((unsigned char) *p) : *p); } putchar(j + 1 < argc ? ' ' : '\n'); } } return 0; }
HELLO WORLD HELLO WORLD HELLO WORLD
This was run as ./prog -n 3 -u hello world. For anything bigger, use a library: POSIX systems provide getopt (and GNU adds getopt_long for --long options).
Exit status
The value main returns is the program's exit status. Scripts and build tools check it: 0 means success, anything else failure. <stdlib.h> defines EXIT_SUCCESS and EXIT_FAILURE, and exit(status) ends the program from anywhere (lesson 50).
Environment variables
getenv reads settings from the environment — another common way to configure a program:
#include <stdio.h> #include <stdlib.h> int main(void) { const char *level = getenv("LOG_LEVEL"); if (level == NULL) level = "info"; // default when not set printf("logging at %s level\n", level); return 0; }
logging at info level
Run as LOG_LEVEL=debug ./prog to change it.
Try it yourself
Write a tiny sum command that adds up all its numeric arguments and reports any that aren't numbers.
skipping "x" sum = 22.5