1 <!DOCTYPE HTML PUBLIC
"-//W3O//DTD W3 HTML 2.0//EN">
2 <!-- This collection of hypertext pages is Copyright 1995, 1996 by Steve Summit. -->
3 <!-- This material may be freely redistributed and used -->
4 <!-- but may not be republished or sold without permission. -->
7 <link rev=
"owner" href=
"mailto:scs@eskimo.com">
8 <link rev=
"made" href=
"mailto:scs@eskimo.com">
9 <title>section
5.10: Command-line Arguments
</title>
10 <link href=
"sx8i.html" rev=precedes
>
11 <link href=
"sx9.html" rel=precedes
>
12 <link href=
"sx8.html" rev=subdocument
>
15 <H2>section
5.10: Command-line Arguments
</H2>
18 <p>The picture at the top of page
115 doesn't quite match the declaration
22 of the situation declared by
24 </pre>which is what
<TT>main
</TT> actually receives.
25 (The array parameter declaration
<TT>char *argv[]
</TT>
26 is rewritten by the compiler to
<TT>char **argv
</TT>,
27 in accordance with the discussion in sections
5.3 and
5.8.)
28 Also, the ``
0'' at the bottom of the array
29 is just a representation of the null pointer
30 which conventionally terminates the
<TT>argv
</TT> array.
31 (Normally, you'll never encounter
32 the terminating null pointer,
33 because if you think of
<TT>argv
</TT> as an array of size
<TT>argc
</TT>,
34 you'll never access beyond
<TT>argv[argc-
1]
</TT>.)
36 <pre> for (i =
1; i
< argc; i++)
37 </pre>looks different from most loops we see in C
38 (which either start at
0 and use
<TT><</TT>,
39 or start at
1 and use
<TT><=
</TT>).
40 The reason is that we're skipping
<TT>argv[
0]
</TT>,
41 which contains the name of the program.
43 <pre> printf(
"%s%s", argv[i], (i
< argc-
1) ?
" " :
"");
44 </pre>is a little nicety to print a space after each word
45 (to separate it from the next word)
46 but
<em>not
</em> after the last word.
47 (The nicety is just that
48 the code
<em>doesn't
</em> print an extra space at the end of the line.)
49 It would also be possible to fold in
50 the following
<TT>printf
</TT> of the newline:
51 <pre> printf(
"%s%s", argv[i], (i
< argc-
1) ?
" " :
"\n");
52 </pre></p><p>As I mentioned in comment on the bottom of page
109,
53 it's not necessary to write pointer-incrementing code like
54 <pre> while(--argc
> 0)
55 printf(
"%s%s", *++argv, (argc
> 1) ?
" " :
"");
56 </pre>if you don't feel comfortable with it.
57 I used to try write code like this,
60 what everybody else did,
61 but it never sat well,
62 and it was always just a bit too hard to write
64 I've reverted to simple, obvious loops like
69 for (argi =
1; argi
< argc; argi++) {
70 printf(
"%s%s", sep, argv[argi]);
76 the original
<TT>argc
</TT> and
<TT>argv
</TT> around later,
78 (This loop also shows another way of handling space separators.)
80 </p><p>Page
116 shows a simple improvement
81 on the matching-lines program first presented on page
69;
82 page
117 adds a few more improvements.
83 The differences between page
69 and page
116 are that
84 the pattern is read from the command line,
85 and
<TT>strstr
</TT> is used instead of
<TT>strindex
</TT>.
86 The difference between page
116 and page
117
87 is the handling of the
<TT>-n
</TT> and
<TT>-x
</TT> options.
88 (The next obvious improvement,
89 which we're not quite in a position to make yet,
90 is to allow a file name to be specified on the command line,
91 rather than always reading from the standard input.)
93 </p><p>Several aspects of this code deserve note.
95 <pre> while (c = *++argv[
0])
96 </pre>is
<em>not
</em> in error.
98 it might look like an example of the classic error of
99 accidentally writing
<TT>=
</TT> instead of
<TT>==
</TT> in a comparison.)
100 What it's actually doing is another version of a combined set-and-test:
101 it assigns the next character pointed to by
<TT>argv[
0]
</TT> to
102 <TT>c
</TT>, and compares it against
<TT>'\
0'
</TT>.
103 You can't see the comparison against
<TT>'\
0'
</TT>,
104 because it's implicit
105 in the usual interpretation of a nonzero expression
107 An explicit test would look like this:
108 <pre> while ((c = *++argv[
0]) != '\
0')
109 </pre><TT>argv[
0]
</TT> is a pointer to a character in a string;
110 <TT>++argv[
0]
</TT> increments that pointer
111 to point to the next character in the string;
112 and
<TT>*++argv[
0]
</TT> increments the pointer
113 while returning the next character pointed to.
114 <TT>argv[
0]
</TT> is not the first string on the command line,
115 but rather whichever one we're looking at now,
116 since elsewhere in the loop we increment
<TT>argv
</TT> itself.
117 </p><p>Some of the extra complexity in this loop is to make sure that
123 the option-parsing loop is
124 <pre> for (
<I>each word on the command line
</I> )
125 if (
<I>it begins with
</I> '-' )
126 for (
<I>each character
</I> c
<I>in that word
</I> )
129 </pre>For comparison,
130 here is another way of writing effectively the same loop:
135 for (argi =
1; argi
< argc
&& argv[argi][
0] == '-'; argi++)
136 for (p =
&argv[argi][
1]; *p != '\
0'; p++)
140 </pre>This uses array notation to access the words on the command line,
141 but pointer notation to access the characters within a word
142 (more specifically, a word that begins with
<TT>'-'
</TT>).
143 We could also use array notation for both:
144 <pre> int argi, chari;
147 for (argi =
1; argi
< argc
&& argv[argi][
0] == '-'; argi++)
148 for (chari =
1; argv[argi][chari] != '\
0'; chari++)
149 switch (argv[argi][chari]) {
152 </pre>In either case,
153 the inner, character loop
154 starts at the second character
155 (index
<TT>[
1]
</TT>),
157 because the first character
160 </p><p>It's easy to see how the
<TT>-n
</TT> option is implemented.
161 If
<TT>-n
</TT> is seen, the
<TT>number
</TT> flag is set to
1
164 in the line-matching loop,
165 each time a line is printed,
166 if the
<TT>number
</TT> flag is true,
167 the line number is printed first.
168 It's harder to see how
<TT>-x
</TT> works.
169 An
<TT>except
</TT> flag is set to
1 if
<TT>-x
</TT> is present,
170 but how is
<TT>except
</TT> used?
171 It's buried down there in the line
172 <pre> if ((strstr(line, *argv) != NULL) != except)
173 </pre>What does that mean?
175 <pre> (strstr(line, *argv) != NULL)
176 </pre>is
1 if the line contains the pattern,
177 and
0 if it does not.
178 <TT>except
</TT> is
0 if we should print matching lines,
179 and
1 if we should print non-matching lines.
180 What we've actually implemented here is an ``exclusive OR,''
181 which is ``if A or B but
<em>not
</em> both.''
182 Other ways of writing this would be
183 <pre> int matched = (strstr(line, *argv) != NULL);
184 if (matched
&& !except || !matched
&& except) {
186 printf(
"%ld:", lineno);
191 <pre> int matched = (strstr(line, *argv) != NULL);
192 if (except ? !matched : matched) {
194 printf(
"%ld:", lineno);
199 <pre> int matched = (strstr(line, *argv) != NULL);
203 printf(
"%ld:", lineno);
211 printf(
"%ld:", lineno);
216 </pre>There's clearly a tradeoff:
217 the last version is in some sense the most clear
218 (and the most verbose),
219 but it ends up repeating the line-number printing
220 and any other processing which must be done for found lines.
221 Therefore, the compressed,
222 perhaps slightly more cryptic forms are better:
224 it's a virtual certainty that more processing will be added for printed lines
226 if we're searching multiple files,
227 we'll want to print the filename for matching lines, too),
228 and if the printing is duplicated in two places,
229 it's far too likely that we'll overlook that fact
230 and add the new code in only one place.
231 </p><p>One last point on the pattern-matching program:
232 it's probably clearer to declare a pointer variable
234 </pre>and set it to the word from
<TT>argv
</TT> to be used as the
235 search pattern (
<TT>argv[
1]
</TT> or
<TT>*argv
</TT>,
236 depending on whether we're looking at page
116 or
117),
237 and then use that in the call to
<TT>strstr
</TT>:
238 <pre> if (strstr(line, pat) != NULL ...
242 <a href=
"sx8i.html" rev=precedes
>prev
</a>
243 <a href=
"sx9.html" rel=precedes
>next
</a>
244 <a href=
"sx8.html" rev=subdocument
>up
</a>
245 <a href=
"top.html">top
</a>
248 This page by
<a href=
"http://www.eskimo.com/~scs/">Steve Summit
</a>
249 //
<a href=
"copyright.html">Copyright
</a> 1995,
1996
250 //
<a href=
"mailto:scs@eskimo.com">mail feedback
</a>