Author : Brian Kernighan
Page : << Previous 7 Next >>
it two string names as arguments, then pro-
ceeded to clobber both of them by incrementation. So how
come we don't lose the original strings in the function that
called strcopy?
As we said before, C is a ``call by value'' language:
when you make a function call like f(x), the VALUE of x is
passed, not its address. So there's no way to ALTER x from
inside f. If x is an array (char x[10]) this isn't a prob-
lem, because x IS an address anyway, and you're not trying
to change it, just what it addresses. This is why strcopy
works as it does. And it's convenient not to have to worry
about making temporary copies of the input arguments.
But what if x is a scalar and you do want to change it?
In that case, you have to pass the ADDRESS of x to f, and
then use it as a pointer. Thus for example, to interchange
two integers, we must write
flip(x, y)
int *x, *y; {
int temp;
temp = *x;
*x = *y;
*y = temp;
}
and to call flip, we have to pass the addresses of the vari-
ables:
flip (&a, &b);
When a C program is called, the arguments on the com-
mand line are made available to the main program as an argu-
ment count argc and an array of character strings argv con-
taining the arguments. Manipulating these arguments is one
of the most common uses of multiple levels of pointers
(``pointer to pointer to ...''). By convention, argc is
greater than zero; the first argument (in argv[0]) is the
command name itself.
Here is a program that simply echoes its arguments.
main(argc, argv)
int argc;
char **argv; {
int i;
for( i=1; i < argc; i++ )
}
Step by step: main is called with two arguments, the argu-
ment count and the array of arguments. argv is a pointer to
an array, whose individual elements are pointers to arrays
of characters. The zeroth argument is the name of the com-
mand itself, so we start to print with the first argument,
until we've printed them all. Each argv[i] is a character
array, so we use a `%s' in the printf.
You will sometimes see the declaration of argv written
as
char *argv[ ];
which is equivalent. But we can't use char argv[ ][ ],
because both dimensions are variable and there would be no
way to figure out how big the array is.
Here's a bigger example using argc and argv. A common
convention in C programs is that if the first argument is
`-', it indicates a flag of some sort. For example, suppose
we want a program to be callable as
prog -abc arg1 arg2 ...
where the `-' argument is optional; if it is present, it may
be followed by any combination of a, b, and c.
main(argc, argv)
int argc;
char **argv; {
...
aflag = bflag = cflag = 0;
if( argc > 1 && argv[1][0] == '-' ) {
for( i=1; (c=argv[1][i]) != '\0'; i++ )
if( c=='a' )
aflag++;
else if( c=='b' )
bflag++;
else if( c=='c' )
cflag++;
else
printf("%c?\n", c);
--argc;
++argv;
}
...
There are several things worth noticing about this
code. First, there is a real need for the left-to-right
evaluation that && provides; we don't want to look at
argv[1] unless we know it's there. Second, the statements
--argc;
++argv;
let us march along the argument list by one position, so we
can skip over the flag argument as if it had never existed _
the rest of the program is independent of whether or not
there was a flag argument. This only works because argv is
a pointer which can be incremented.
The switch statement can be used to replace the multi-
way test we used in the last example. When the tests are
like this:
if( c == 'a' ) ...
else if( c == 'b' ) ...
else if( c == 'c' ) ...
else ...
testing a value against a series of constants, the switch
statement is often clearer and usually gives better code.
Use it like this:
switch( c ) {
case 'a':
aflag++;
break;
case 'b':
bflag++;
break;
case 'c':
cflag++;
break;
default:
printf("%c?\n", c);
Page : << Previous 7 Next >>