Our First Slightly Realistic Program

Now we're ready to write a program that vaguely resembles a solution to a real problem. We'll start with a simple, rural type of programming problem.

Imagine that you are at a county fair. The contest for the heaviest pumpkin is about to get underway, and the judges have asked for your help in operating the “pumpkin scoreboard”. This device has a slot for the current pumpkin weight (the CurrentWeight slot), and another slot for the highest weight so far (the HighestWeight slot). Each slot can hold three digits from 0 to 9 and therefore can indicate any weight from 0 to 999. The judges want you to maintain an up-to-date display of the current weight and of the highest weight seen so far. The weights are expressed to the nearest pound. How would you go about this task?

Probably the best way to start is by setting the number in both slots to the weight of the first pumpkin called out. Then, as each new weight is called out, you change the number in the CurrentWeight slot to match the current weight; if it's higher than the number in the HighestWeight slot, you change that one to match as well. Of course, you don't have to do anything to the HighestWeight slot when a weight less than the previous maximum weight is called out, because a pumpkin with a lesser weight can't be the winner. How do we know when we are done? Since a pumpkin entered in this contest has to have a weight of at least 1 pound, the weigher calls out 0 as the weight when the weighing is finished. At that point, the number in the HighestWeight slot is the weight of the winner.

The procedure you have just imagined performing can be expressed a bit more precisely by the following algorithm:

1.
Ask for the first weight.

2.
Set the number in the CurrentWeight slot to this value.

3.
Copy the number in the CurrentWeight slot to the HighestWeight slot.

4.
Display both the current weight and the highest weight so far (which are the same, at this point)

5.
While the CurrentWeight value is greater than 0 (that is, there are more pumpkins to be weighed), do steps a to d:

a. Ask for the next weight.

b. Set the number in the CurrentWeight slot to this weight.

c. If the number in the CurrentWeight slot is greater than the number in the HighestWeight slot, copy the number in the CurrentWeight slot to the HighestWeight slot.

d. Display the current weight and the highest weight so far.

6.
Stop. The number in the HighestWeight slot is the weight of the winner.

Figure 3.24 is the translation of our little problem into C++.

Figure 3.24. A C++ program (codepump1.cpp)


Susan had a question about the formatting of the output statement cout << "Highest weight " << HighestWeight << endl;.

Susan: Why do we need both "Highest weight" and HighestWeight in this line?

Steve: Because "Highest weight" is displayed on the screen to tell the user that the following number is supposed to represent the highest weight seen so far. On the other hand, HighestWeight is the name of the variable that holds that information, so including HighestWeight in the output statement will result in displaying the highest weight we've seen so far on the screen. Of course, the same analysis applies to the next line, which displays the label "Current weight" and the value of the variable CurrentWeight.

You've already seen most of the constructs that this program contains, but we'll need to examine the role of the preprocessor directive #include <iostream>, which we've used before without much explanation. A #include statement causes the compiler to pretend that the code in the included file was typed in instead of the #include statement. In this particular case, <iostream> is the file that tells the compiler how to use the standard C++ I/O library.

The term preprocessor directive is a holdover from the days when a separate program called the preprocessor handled functions such as #include before handing the program over to the compiler. Nowadays, these facilities are provided by the compiler rather than by a separate program, but the name has stuck.

In this particular case, <iostream> defines the I/O functions and variables cout, cin, <<, and >>, along with others that we haven't used yet. If we left this line out, none of our I/O statements would work.

Susan also had some questions about variable names:

Susan: Tell me again what the different shorts mean in this figure. I am confused, I just thought a short held a variable like i. What is going on when you declare HighestWeight a short? So do the “words” HighestWeight work in the same way as i?

Steve: A short is a variable. The name of a short, like the name of any other variable, is made up of one or more characters; the first character must be a letter or an underscore (_), while any character after the first must be either a letter, an underscore, or a digit from 0 to 9. To define a short, you write a line that gives the name of the short. This is an example:

short HighestWeight;

Susan: OK, but then how does i take 2 bytes of memory and how does HighestWeight take up 2 bytes of memory? They look so different, how do you know that HighestWeight will fit into a short?

Steve: The length of the names that you give variables has nothing to do with the amount of storage that the variables take up. After the compiler gets through with your program, there aren't any variable names; each variable that you define in your source program is represented by the address of some area of storage. If the variable is a short, that area of storage is 2 bytes long; if it's a char, the area of storage is 1 byte long.

Susan: Then where do the names go? They don't go “into” the short?

Steve: A variable name doesn't “go” anywhere; it tells the compiler to set aside an area of memory of a particular length that you will refer to by a given name. If you write short xyz; you're telling the compiler that you are going to use a short (that is, 2 bytes of memory) called xyz.

Susan: If that is the case, then why bother defining the short at all?

Steve: So that you (the programmer) can use a name that makes sense to you. Without this mechanism, you'd have to specify everything as an address. Isn't it easier to say

HighestWeight = CurrentWeight;

rather than

mov ax,[1000]
mov [1002],ax

or something similar?

The topic of #include statements was the cause of some discussion with Susan. Here's the play by play:

Susan: Is the include command the only time you will use the # symbol?

Steve: There are other uses for #, but you won't see any of them for a long time.[40]

[40] Not until “Definitions” on page 852 in Chapter 12, to be exact.

Susan: So #include is a command.

Steve: Right; it's a command to the compiler.

Susan: Then what are the words we have been using for the most part called? Are those just called code or just statements? Can you make a list of commands to review?

Steve: The words that are defined in the language, such as if, while, for, and the like are called keywords. User defined names such as function and variable names are called identifiers.

Susan: So <iostream> is a header file telling the compiler that it is using info from the iostream library?

Steve: Essentially correct; to be more precise, when we include <iostream>, we're telling the compiler to look into <iostream> for definitions that we're going to use.

Susan: Then the header file contains the secondary code of machine language to transform cin and cout into something workable?

Steve: Close, but not quite right. The machine code that makes cin and cout do their thing is in the iostream part of the standard library. The header file gives the compiler the information it needs to compile your references to cout, cin, <<, and >> into references to the machine code in the library.

Susan: So the header file directs the compiler to that section in the library where that machine code is stored? In other words, it is like telling the compiler to look in section XXX to find the machine code?

Steve: The header file tells the compiler what a particular part of the library does, while the library contains the machine code that actually does it.

If you have previous experience as a programmer (other than in C), you may wonder why we have to tell the compiler that we want to use the standard I/O library. Why doesn't the compiler know to use that library automatically? This seeming oversight is actually the result of a decision made very early in the evolution of C: to keep the language itself (and therefore the compiler) as simple as possible, adding functionality with the aid of standard libraries. Since a large part of the libraries can be written in C (or C++), this decision reduces the amount of work needed to “port” the C (or C++) language from one machine architecture or operating system to another. Once the compiler has been ported, it's not too difficult to get the libraries to work on the new machine. In fact, even the C (or C++) compiler can be written in C (or C++), which makes the whole language quite portable. This may seem impossible. How do you get started? In fact, the process is called bootstrapping, from the impossible task of trying to lift yourself by your own bootstraps.[41] The secret is to have one compiler that's already running, then you use that compiler to compile the compiler for the new machine. Once you have the new compiler running, it is common to use it to compile itself so that you know it's working. After all, a compiler is a fairly complex program, so getting it to compile and execute properly when it's compiling itself is a pretty good indication that it's producing the right code.

[41] If this term sounds familiar, that's because we've already seen it in the context of how we start up a computer when it's turned on, starting from a small boot program in the ROM, or Read-Only Memory.

Most of the rest of the program should be fairly easy to understand, except for the two lines int main() and return 0;, which have related functions. Let's go into the line int main() in a little more detail than we have already discussed. As previously mentioned, the purpose of the main() part of this line is to tell the compiler where to start execution; the C++ language definition specifies that execution always starts at a block called main. This may seem redundant, as you might expect the compiler to assume that we want to start execution at the beginning of the program. However, C++ is intended to be useful in the writing of very large programs; such programs can and usually do consist of several implementation files, each of which contains some of the functionality of the program. Without such a rule, the compiler wouldn't know which module should be executed first.

The int part of this same line specifies the type of the exit code that will be returned from the program by a return statement when the program is finished executing; in this case, that type is int. The exit code can be used by a batch file to determine whether our program finished executing correctly, and an exit code of 0, by convention, means that it did.[42] The final statement in the program is return 0;. This is the return statement just mentioned, whose purpose is to return an exit code of 0 when our program stops running. The value that is returned, 0, is an acceptable value of the type we declared in the line int main(), namely, int; if it didn't match, the compiler would tell us we had made an error.

[42] A batch file is a text file that directs the execution of a number of programs, one after the other, without manual intervention. A similar facility, generically referred to as scripting, is available in most operating systems.

Finally, the closing curly brace, }, tells the compiler that it can stop compiling the current block, which in this case is the one called main. Without this marker, the compiler would tell us that we have a missing }, which of course would be true.

Susan Tries to Write the Pumpkin Program Herself

Susan decided a little later in our collaboration that she wanted to try to reproduce this program just by considering the English description, without looking at my solution. She didn't quite make it without peeking, but the results are illuminating nevertheless.

Susan: What I did was to cover your code with a sheet of paper and just tried to get the next line without looking, and then if I was totally stumped then I would look. Anyway, when I saw that if statement then I knew what the next statement would be but I am still having problems with writing backwards. For example

if (CurrentWeight > HighestWeight)
  HighestWeight = CurrentWeight;

That is just so confusing because we just want to say that if the current weight is higher than the highest weight, then the current weight will be the new highest weight, so I want to write CurrentWeight = HighestWeight. Anyway, when I really think about it I know it makes sense to do it the right way; I'm just having a hard time thinking like that. Any suggestions on how to think backward?

Steve: What that statement means is “set HighestWeight to the current value of CurrentWeight.” The point here is that = does not mean “is equal to”; it means “set the variable to the left of the = to the value of the expression to the right of the =”. It may not be a very clear way of saying that, but that's what it means.

Susan: With all the { and } all over the place, I was not sure where and when the return 0; came in. So is it always right before the last }? OK, now that I think about it, I guess it always would be.

Steve: You have to put the return statement at a place where the program is finished with whatever it was doing. That's because whenever that statement is executed, the program is going to stop running. Usually, as in this case, you want to do that at the physical end of main.

Susan: Anyway, then maybe I am doing something wrong, and I am tired, but after I compiled the program and ran it, I saw that the HighestWeight label was run in together with the highest number and the next sentence, which said "Please enter the next weight".

All those things were on the same line and I thought that looked weird; I tried to fix it but the best I had the stamina for at the moment was to put a space between the " and the P, to at least make a separation.

Steve: It sounds as though you need some endls in there to separate the lines.

Try the Pumpkin Program Yourself

You can try this program out yourself. The name of the source code file is pump1.cpp, and you can compile it and execute it just as you did with the sample program when you installed the compiler. If you run the compiled program under the debugger and wonder about the seemingly meaningless values that the debugger shows for variables before the first statement that sets each one to a value, let me assure you that they are indeed meaningless. I'll explain why that is in the next chapter.

We're almost done with this chapter, but first let's practice a little more with chars and strings.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset