Command line arguments: argc and argv
Until now, we have been writing our main function as:
int main () {
...
It turns out that main can also accept some parameters.
The first parameter is an integer, usually called argc, that
tells how many command line arguments there are, including the
command itself. The command
line arguments describe what the Unix command line looked like when
the program was executed. The second argument to main, usually called
argv, is an array of strings. A string is just an array of
characters, so argv is an array of arrays. There are standard
C functions that manipulate strings, so it's not too important to
understand the details of argv, as long as you see a few examples
of using it.
For example, suppose you want to just look at the command line arguments
to a program. The printf %s token prints strings,
just like %i prints integers:
#include <stdio.h>
int main (int argc, char *argv[]) {
int i;
for (i=0; i<argc; i++) printf ("%s\n", argv[i]);
exit (0);
}
Let's call this program foo, so we would compile it with
cc -o foo foo.c
If the user simply executes it like this:
runner% foo
then the output would be
foo
argc would be 1, and argv[0] would be the string "foo".
If the user types
runner% foo 1 2 3 hello
then the output would be
foo
1
2
3
hello
argc would be 5.
Suppose we want to write a program that accepts two command line arguments
and prints their sums:
#include <stdio.h>
int main (int argc, char *argv[]) {
int a, b;
if (argc != 3) {
fprintf (stderr, "wrong number of arguments!\n");
exit (1);
}
a = atoi (argv[1]);
b = atoi (argv[2]);
printf ("%i\n", a + b);
exit (0);
}
The two calls to atoi convert the strings argv[1]
and argv[2] to integers. atoi stands for
"ASCII to integer."
It's important to remember that argc is always one more than
the number of command line arguments, since it also includes the name
of the program in argv[0]. So if your program expects only
one argument, it should make sure argc is equal to 2, then
look for that argument in argv[1].
More on Arrays
Let's look at some more programs using arrays.
Suppose we have a file full of student grades, and we want to see which
grades are above average. We can read the grades into an array, find the
average, then go through the array printing out each grade that is above
average:
#include <stdio.h>
#define MAX_STUDENTS 100
int main () {
int nstudents, i;
float grades[MAX_STUDENTS], sum, avg;
nstudents = 0;
/* loop, filling the array with values from scanf */
for (;;) {
scanf ("%f", &grades[nstudents]);
if (feof (stdin)) break;
nstudents++;
/* too many? complain and exit */
if (nstudents > MAX_STUDENTS) {
fprintf (stderr, "too many students!\n");
exit (1);
}
}
/* nothing on stdin? complain and exit. */
if (nstudents == 0) {
fprintf (stderr, "not enough students!\n");
exit (1);
}
/* find average of grades in array */
sum = 0.0;
for (i=0; i<nstudents; i++) sum += grades[i];
avg = sum / nstudents;
/* go through printing grades that are above average */
for (i=0; i<nstudents; i++)
if (grades[i] > avg) printf ("%f\n", grades[i]);
exit (0);
}
Functions and Arrays
Functions can accept array parameters. Usually the size of the array
must be specified to the function, since there's no way to tell the size
of an array once it has been passed as a parameter. The following function
will return the average of the first n floats in the
array v:
float find_average (float v[], int n) {
int i;
float sum;
for (i=0,sum=0.0; i<n; i++) sum += v[i];
return sum / n;
}
Because of some weird things going on behind the scenes (trust me,
you don't want to know), arrays passed to functions are not passed
by value; if an array element is changed in the function, it remains
changed in the original array. This makes things more efficient
since a new copy of the array doesn't have to be made, but you have
to be careful not to change the contents of an array in a function unless
you really mean it. Usually this isn't a problem; in fact, it often
comes in handy. The following function will initialize the first
n elements of an integer array to 0:
void initialize_to_zero (int w[], int n) {
int i;
for (i=0; i<n; i++) w[i] = 0;
}
This way, you can initialize lots of different arrays without having to
write lots of different for loops.