CHAPTER 11
|
Table of Contents
Learning C++:
An Index of Entry Points
2. The A reference document on the basic elements of C++.
3. The Patterns
|
Programmers often make a distinction between
compile time and run time. Compile time is the period when a
program is being compiled, while run time is the period when a program is
running. The distinction is important, for example, in terms of the
different types of errors that can occur. By this time you have seen many
compile time error messages - error messages generated by syntactic errors
in your code. In contrast, run time errors involve such things as trying
to divide by 0. Such an error would not be caught at compile time because,
at that point, the system does not know the values of the variables. Dynamic vs. static memory allocation is also a compile time vs. a run
time issue. As you know, when a program is finished compiling, all the
instructions necessary to allocate memory for the program's variables and
constants have been written. At this point, one could calculate all the
static memory required of a program before running it and see if a given
computer was capable of providing the required memory. Dynamic memory, on
the other hand, is requested during run time and, in may cases, there is
no way to know ahead of time how much memory will be required - although
one can make estimates. A. Run Time Parameters Anyone who knows 'DOS' knows that one can write the following command
at the prompt:
which, of course, means to copy 'file1.txt' into 'file2.txt'. What some
may not realize is that 'copy' is a program and 'file1.txt' and
'file2.txt' are values being passed to this program. In C++, if we wish to
use such run time parameters in a program, we need to declare
'main' with two parameters. The first parameter tells the system how many
parameters there are and the second parameter is an array of strings where
each array element is one of the parameters. When we run the program (by
typing the program's name at the operating system prompt, the parameters
are passed to 'main'. For example, suppose we want to write our own version of 'copy'. We
would create a file called 'copy' and place our 'main' in that file. The
declaration for that 'main' would look as follows:
The two parameter names 'argc' and 'argv' can be different but they are
the standard ones used in C++. The first one holds the number of arguments
in the run time call to the program. Interestingly enough, the name of the
program is considered a parameter. Thus, if the following is typed at the
operating system prompt:
the parameter 'argc' will hold the value 2. B. Multi-Dimensional Arrays FIGURE 11.4 DRAW an array with one name However, an array of strings is two dimensional in the sense
that a good picture for it would be: Figure 11.5 DRAW a 'table' of names. Of course, one can have two-dimensional arrays of integers or other
types for that matter. For example, if you wanted to record the
temperature for each day of each month you could use an array with 31
columns and 12 rows - see Figure 11.6.
The declaration for this would be:
As an another example, suppose we wanted an array of 20 strings, where
each string represented a name. If the maximum size of a name was 40, this
array could be declared as:
To output the temperature on day 3 of the 10th month, one might write
the code:
To output the 15th character of the fourth name one might write the
code:
Two points about this:
When one wants to access a whole row of a two dimensional array at the
same time, one only uses the first array index. This would not make sense
with our temperature array but since strings can be handled as a unit, it
makes sense, for example, to write:
to output the 4th name in the array called 'names'. (Of course, the
names better have been stored with null terminating characters or we will
have problems with this output.) C. The Meaning of 'Char**' to represent a string - called name. Since a string is an array, an
array of strings is an array of arrays. Using the language of pointers, an
array of arrays of some type can be spoken of as a pointer to a pointer to
some type. In our case, a pointer to a pointer to a char or 'char**'. Although this pointer based representation is somewhat ugly, it is the
only way to represent the data coming into the program. Note that we have
no idea how large the strings will be or how many there will be. In such a
situation, the pointer-based approach must be used to allow the system to
allocate the required amount of memory. Here is the code for the whole 'copy' program: Notice how the two parameters are used. The program uses 'argc'
to make sure that the correct number of parameters have been entered. It
then uses the string in array element 'argv[1]' as the name of the input
file and the array element 'argv[2]' as the name of the output file. In
other words, the strings in the parameter 'argv' are the parameters passed
to the program at run time. (By the way, 'argv[0]' holds the string 'copy'
- the name of the program.) The rest of the code takes advantage of ideas we have already
discussed. However, the test in the 'while' loop might be a bit puzzling.
We have two files that are being worked with each time through the loop
and we need to make sure both files are OK. In the case of the output file
the loop will terminate only if a problem occurs such as if there is no
more room on the disk. The input test is a bit more complex. The stream
'inFile' will have an 'error' condition either if some problem occurs or
if the end-of-file marker is encountered. While 'end-of-file' is not
really an error, it does set to TRUE the value of the 'fail' flag and thus
we can use 'inFile' to check for the end of the file. In this way, the
while loop will terminate when there are no more characters to read in the
file to be copied.
|