The main()
function in a C program most often takes the following form.
int main (int argc, const char * argv[]) { }
The parameters argc
and argv
are used to read command line parameters. These notes will explain how the command line mechanism works in C.
The C programming language was developed in conjunction with the UNIX operating system. Originally UNIX was a command-line oriented operating system. Most users of UNIX would get work done by typing text commands at a command line to invoke programs.
One interesting feature of the UNIX command line is that users could pass parameters to programs when invoking them. For example, if we wrote a C program that compiles to a program named 'foo', we could start the program from the command line by typing
./foo
If the program is constructed to accept parameters from the command line we could also start the program and pass it some parameters by typing
./foo 123 bar
When the program starts, it will receive the additional command line parameters in the form of an array of text strings passed to main
.
As you can see above, main has two parameters. The first parameter, argc
, is an integer count of how many command line parameters the user typed when invoking the program. The second parameter, argv
, is an array of text strings containing the actual parameters the user typed. The name of the program itself is always considered the first parameter, and additional parameters are stored as subsequent entries in the array.
For example, if the user invoked our program by typing
./foo 123 bar
at the command line, main would receive an argc
parameter with value 3 and an argv
parameter containing the three text strings "./foo"
, "123"
, and "bar"
. The program can extract useful information from the array of strings by using the sscanf
function to scan in the contents of a string. For example, to convert the parameter "123"
to an integer the program would do
int x; sscanf(argv[1],"%d",&x);
Here is the code for an example program that makes use of a couple of command line parameters.
#include <stdio.h> int main (int argc, const char * argv[]) { int x, N,n; // The user will pass us a seed value and a value for N // via command line arguments. Since the name of the // program is always the first argument, check to see // that 3 arguments are present. If we see anything // other than 3 arguments, just quit with an error // message. if(argc != 3) { printf("Invalid argument list.\n"); printf("Usage: Random <seed> <N>\n"); return -1; } // Read x and N from the arguments sscanf(argv[1],"%d",&x); sscanf(argv[2],"%d",&N); n = 0; while(n < N) { // Generate the next number in the sequence // Mod by 11657 to keep the numbers in a // modest range. x = (17389*x+12553)%11657; n++; // Print the number we just generated. // Since we want to print numbers in the // range from 0 to 999 we have to mod x // by 1000 to get the desired value. printf("%d\n",x%1000); } return 0; }
This program generates a pseudo-random sequence of integers and prints it to the console. The seed, or starting, value for the sequence and the number of numbers to generate are both passed as command line parameters to the program. Near the top of main the program scans those parameters and uses them to set up the logic for what follows.
Suppose that the code for the example program above is stored in a c source code file named random.c. To compile this program from the command line we can use the command
gcc random.c -o random
The -o
option used here allows us to specify the name of the executable that gets generated when we compile random.c
.
Once we have compiled the program we can run it by typing
./random 392 10
This will cause the program to generate 10 random integers starting from a seed value of 392.
Another technique that is commonly used with programs on the command line is redirection. In this technique you redirect the input or output stream for a program. For example, you can redirect the standard output for a program to a file.
To run our random number generating program and redirect the output to a file named "random.txt" we can do
./random 102 100 > random.txt
You can also use redirection to force a program to take its input from a file instead of from the keyboard. I will show an example of this below.
Command line programs that read parameters from the command line and print output to the console are an important part of the Unix ecosystem. A common trick that Unix users will apply with these sorts of programs is piping several short programs together.
One common application of piping is to send the output from one program to another program for further processing. Often, the second program is one of the standard Unix command line utilities, which will perform additional processing on the output of the first program. Here is a typical example. Suppose we wanted to run our random number generator and see only the numbers it outputs that start with the digit 5. We can accomplish this by piping the output of the random program to the Unix grep
utility. grep
is a utility program that scans lines of input text looking for patterns. In the example below, I tell grep
to scan the output generated by the random program looking for lines that start with the digit 5.
./random 120 30 | grep ^5
You can use this technique to chain together two or more of your own programs. The random number generating program I wrote above can serve as a handy source for a stream of random numbers that can be piped to other programs. Below is the source code for a program that does a simple example of a Monte Carlo simulation, which uses a stream of random numbers to simulate a simple physical process. In this case, the process is a simulation of darts being thrown at random at a dart board. The dart board is a circle whose radius R is given by a command line parameter. The program reads N pairs of integers from the keyboard to simulate N darts thrown at a dart board. The dart board sits at the origin and fits in a square of sides 2 R. By counting how many darts land within R of the origin, we can develop a very crude estimate for π.
#include <stdio.h> int main (int argc, const char * argv[]) { int R, N, n, inCircle, x, y; // The user will pass us a radius R and a value for N // via command line arguments. Since the name of the // program is always the first argument, check to see // that 3 arguments are present. If we see anything // other than 3 arguments, just quit with an error // message. if(argc != 3) { printf("Invalid argument list.\n"); printf("Usage: Darts <R> <N>\n"); return -1; } // Read R and N from the arguments sscanf(argv[1],"%d",&R); sscanf(argv[2],"%d",&N); n = 0; inCircle = 0; while(n < N) { // Read the coordinates of the next dart scanf("%d",&x); scanf("%d",&y); // Recenter the point to make it fall in the square. x = x%(2*R)-R; y = y%(2*R)-R; // Is the dart within R of the origin? if(x*x+y*y <= R*R) inCircle++; n++; } // The ratio inCircle/N will produce an estimate for Pi/4. // By multiplying by 4.0 we can generate a crude estimate // for Pi. printf("%f\n",4.0*inCircle/N); return 0; }
If we compile this code to a program named darts, we can pipe the output of the random program to the darts program to get an estimate for π:
./random 120 1000 | ./darts 500 500
We can also use the redirection technique to redirect the output of the Random program to a file and then redirect that file into the input of the Darts program:
./random 120 1000 > random.txt ./darts 500 500 < random.txt
As an alternative to compiling these programs we can use a make system to build the programs. The Linux make
utility makes it easy to compile one or more files in a project.
The first step in using make
is to create a makefile. A makefile is a text file with the name 'Makefile' that you put in the same directory as your source code files.
Here is the makefile for our project:
all: random darts random: random.c gcc random.c -o random darts: darts.c gcc darts.c -o darts test: random darts ./random 932 1000 > random.txt ./darts 500 500 < random.txt
A makefile is a list of one or more targets. Each target has the form
<target name>: <dependencies> <build commands>
The <dependencies>
are a list of one or more source code files or the names of other targets. The line or lines containing the build commands all have to start with a tab.
For example, the target to build the random
program is
random: random.c gcc random.c -o random
This says that the target random
depends on the C source code file random.c
. Whenever the source code file gets modified the make system will automatically recompile the random
program when we run the make
command.
Once we have set up the makefile we can rebuild all the programs in our project by simply typing the command
make
in the terminal. When you run make
in this way it looks for a file named
Makefile
in the currect directory and tries to build the first target listed there. In this example the first target is the all
target, which in turn depends on the random
and darts
targets. If either of those files needs to be recompiled make
will run the commands listed to rebuild them.
The example make file also contains a test
target that will recompile the programs if any changes have been made and then run a couple of simple tests to test the two programs. To execute this target we run the command
make test
in the terminal.