Words After the Program's Name

Every main you have written declared int main(void): I take nothing. But when you type gcc -std=c89 program.c into a shell, gcc receives those extra words from somewhere, and that somewhere is main's second standard form:

int main(int argc, char *argv[])

Both forms are equally standard; you choose per program. argc is the argument count, and argv is an array of strings, which after chapter 11 you can read precisely: an array of char *, each pointing to one NUL-terminated word the user typed. The operating system splits the command line on whitespace and hands your program the pieces before the first statement of main runs.

Counting and Walking the Arguments

This platform's runner launches programs with no arguments, so here it prints:

argc = 1
argv[0] = /tmp/out
argv[argc] is NULL

The two surprises are both visible. First, argc counts argv[0], which is the program's own name (here, the path the sandbox compiled it to), so a program run with no arguments still has argc == 1, and ./prog data.txt 42 has argc == 3 with the real arguments living in argv[1] and argv[2]. Second, the standard guarantees argv[argc] is NULL, a sentinel after the last argument, the same end-marker idea as the '\0' inside each string, one level up. On your own machine, ./prog one two would print five lines: an argc of 3, three pointers, and the NULL confirmation.

From Text to Numbers

Arguments arrive as strings even when the user meant numbers; "42" is three bytes of text, not an int. ANSI C offers two converters in <stdlib.h>, one convenient and one honest:

With no arguments it converts its built-in "42"; run on a real machine, ./prog 137 converts what you typed. atoi(text) is the convenient one, and its convenience is a trap: on failure it returns 0 with no error signal, so atoi("banana") and atoi("0") are indistinguishable, a guard-free design from an era this course has spent twelve chapters arguing against.

strtol(text, &end, 10) is the honest one. It converts in base 10 and writes a pointer to the first unconverted character through end, chapter 11's pointer-parameter idiom letting one call return two results. The guard reads exactly like the sentinel checks you know: end == text means nothing converted at all, and *end != '\0' means the number ended before the string did ("42x"). Pass end == text and land on '\0', and the whole argument was a clean number. Prefer strtol anywhere the input is the user's to get wrong, which is everywhere.

Validate Before You Touch

argv[i] is only yours to read for i < argc; reaching past the count is the same out-of-bounds indexing chapter 9 named undefined behaviour. So a program that needs an argument checks argc first, and this chapter supplies the canonical customer, a program that opens the file the user names:

Run here without arguments, it takes the first exit and prints usage: /tmp/out <filename>, which is precisely correct behavior: the argc guard fired before any touch of argv[1]. The usage line is a tiny act of professionalism, using argv[0] so the message names the program however the user invoked it (real tools send it to stderr, the error stream from last lesson's table). Then the familiar chain: fopen the name the user gave, check for NULL, close what you opened. On a real machine, ./prog notes.txt either opens the file or tells you why not.

Why Arguments Beat Prompts

You could get a filename with a prompt and fgets instead, and interactively that feels friendlier. But a program that prompts can only be driven by a human, while a program that takes arguments can be driven by anything: a shell loop over a thousand files, a makefile, a cron job, another program. That is why every tool you have used this course, gcc included, is argument-driven, and why the shell exists at all: programs whose inputs live on the command line compose into pipelines and scripts, and programs that stop to ask questions do not. Prompts are for conversations; arguments are for tools.

Key Takeaways

  • int main(int argc, char *argv[]) is main's second standard form: argc counts the arguments, argv is an array of char * to NUL-terminated strings.
  • argv[0] is the program's name and is counted, so ./prog data.txt 42 has argc 3; argv[argc] is guaranteed NULL.
  • Check argc before reading argv[i]; indexing past the count is undefined behaviour, and a usage message naming argv[0] is the polite failure.
  • atoi returns 0 on failure with no error signal, indistinguishable from a real "0"; strtol with an end-pointer check (end == text || *end != '\0') is the guarded converter.
  • Arguments beat prompts because they make programs scriptable: shells, makefiles, and other programs can supply arguments, but only a human can answer a prompt.