Skip to content

Commit 6e64a4f

Browse files
committed
CLI arg parsing
1 parent e433aef commit 6e64a4f

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

15-Appendices.md

+97
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,109 @@ You may find it useful to have a couple of PuTTY windows open, so that you can m
174174

175175
# Parsing command-line arguments in C++
176176

177+
Throughout this book you'll find commands like `ls -l` or `grep needle haystack.txt`.
178+
Everything following the command name (`ls` or `grep`) is a command *argument*.
179+
You too can write programs that take arguments!
180+
181+
In C++, the arguments given to a command are passed as parameters to your `main` function.
182+
Instead of writing `int main()`, your `main` function will take two arguments:
183+
184+
- An `int` which gives the number of arguments passed on the command line.
185+
- A `char**` which is an array of NTCAs[^2d] (also known as C-strings) which are the string values of the arguments passed.
186+
187+
These arguments are traditionally named `argc` and `argv`, for "argument count" and "argument values", respectively.
188+
You can name them whatever you like, however; C++ doesn't care.
189+
190+
Let's do an example: here is a program that prints its arguments out to the screen, one per line:
191+
192+
```C++
193+
#include<iostream>
194+
using namespace std;
195+
196+
int main(int argc, char** argv)
197+
{
198+
cout << "Index\tArgument" << endl;
199+
for(int i = 0; i < argc; i++)
200+
{
201+
cout << i << "\t" << argv[i] << endl;
202+
}
203+
204+
return 0;
205+
}
206+
```
207+
208+
Let's run it and see what happens:
209+
210+
```
211+
$ ./print a b c
212+
Index Argument
213+
0 ./print
214+
1 a
215+
2 b
216+
3 c
217+
```
218+
219+
The "0th" argument is always passed; it is the name of the program that was run.
220+
So the first argument on the command line is at `argc[1]`, and so on.
221+
222+
For a practical example, let's write a program that counts the number of lines in a file (like `wc -l`, but less fancy).
223+
If the user doesn't pass us exactly one file, we want to print out a message telling them how to use the program;
224+
otherwise, we should open the file and count the number of newlines in it.
225+
226+
```{.cpp .numberLines}
227+
#include<iostream>
228+
#include<fstream>
229+
using namespace std;
230+
231+
int main(int argc, char** argv)
232+
{
233+
if(argc != 2)
234+
{
235+
cout << "Counts the number of newlines in the given filename"
236+
<< endl << "Usage: " << argv[0] << " [<filename>]" << endl;
237+
return 1; // exit the program
238+
}
239+
240+
ifstream fin(argv[1]);
241+
char buffer;
242+
int newline_count = 0;
243+
244+
while(fin.get(buffer))
245+
{
246+
if(buffer == '\n')
247+
{
248+
newline_count++;
249+
}
250+
}
251+
252+
fin.close();
253+
254+
cout << argv[1] << " has " << newline_count << " lines." << endl;
255+
256+
return 0;
257+
}
258+
```
259+
260+
In this example, you can see the use of `argv[0]` to display the program name
261+
It is a common pattern to check the arguments passed before doing anything else and exit the program if they are incorrect.
262+
Finally, we can use `argv[1]` as we would any other NTCA.
263+
We could even access the individual characters of the filename by doing something like `argv[1][0]`.
264+
265+
Now, you may be wondering, "how do I get fancy-dancy options parsing, like `ls` and friends?"
266+
Well, there are a few options.
267+
The classic choice is [`getopt`](https://www.gnu.org/software/libc/manual/html_node/Getopt.html),
268+
but the C standard library also has [a few other options](https://www.gnu.org/software/libc/manual/html_node/Parsing-Program-Arguments.html).
269+
Boost also has a C++-style library for argument parsing, [program_options](http://www.boost.org/doc/libs/1_65_0/doc/html/program_options.html).
270+
Or, you can write your own!
271+
177272
# Submitting homework with Git
178273

179274

180275
[^another]: Windows is also an operating system.
181276
[^google]: Uh... Google it.
182277
[^pun]: Pun intended.
278+
[^2d]: Yep, it's a two-dimensional array. We use `char**` rather than something like `char[][100]` since we don't know how big the array or its subarrays will be;
279+
the operating system works this out when it runs your program.
183280

184281
<!-- LocalWords: PuTTY
185282
-->

0 commit comments

Comments
 (0)