TOC PREV NEXT INDEX


I've just released a deduplicating backup product for
VMWare Workstation and Server.
Do you need to reduce the storage needed to maintain multiple backups?
Or do you need multiple snapshots on VMWare Server?
If you have either of these needs, just click
here to get started for only $29 (limited time offer ends July 31st, 2011)!

C++: A Dialog


CHAPTER 3 Basics of Programming
After that necessary detour into the workings of the hardware, we can now resume our regularly scheduled explanation of the creative possibilities of computers. It may sound odd to describe computers as providing grand scope for creative activities: Aren't they monotonous, dull, unintelligent, and extremely limited? Yes, they are. However, they have two redeeming virtues that make them ideal as the canvas of invention: They are extraordinarily fast and spectacularly reliable. These characteristics allow the creator of a program to weave intricate chains of thought and have a fantastic number of steps carried out without fail. We'll begin to explore how this is possible after we go over some definitions and objectives.
3.1. Definitions
An identifier is a user defined name; variable names are identifiers. Identifiers must not be spelled the same as keywords such as if and while; for example, you cannot create a variable with the name while.
A keyword is a word defined in the C++ language such as if and while. It is illegal to define an identifier such as a variable name that is spelled the same as a keyword.
The C++ standard library is a collection of code defined by the ISO (International Standards Organization) that must be included with every standards-compliant compiler. Unfortunately, as of this writing, there are no completely standards-compliant compilers, but the one on the CD in the back of the book should be close enough for programs you will be writing.
A C string literal is a literal value representing a variable number of characters. An example is "This is a test.". C string literals are surrounded by double quotes (").
A block is a section of code that acts like one statement, as far as the language is concerned; that is, wherever a statement can occur, a block can be substituted, and it will be treated as one statement for the purposes of program organization.

3.2. Objectives of This Chapter

By the end of this chapter, you should
1. Understand what a program is and have some idea how one works.
2. Understand how to get information into and out of a program.
3. Understand how to use if and while to control the execution of a program.1
4. Understand how a portion of a program can be marked off so that it will be treated as one unit.
5. Be able to read and understand a simple program I've written in C++.

3.3. Rapid and Accurate Calculation

The most impressive attribute of modern computers, of course, is their speed; as we have already seen, this is measured in MIPS (millions of instructions per second).

Of course, raw speed is not very valuable if we can't rely on the results we get. ENIAC, one of the first electronic computers, had a failure every few hours, on the average; since the problems it was solving took about that long to run, the likelihood that the results were correct wasn't very high. Particularly critical calculations were often run several times, and if the users got the same answer twice, they figured it was probably correct. By contrast, modern computers are almost incomprehensibly reliable. With almost any other machine, a failure rate of one in every million operations would be considered phenomenally low, but a computer with such a failure rate would make thousands of errors per second.2

The Real Reason for "Computer Problems"

On the other hand, if computers are so reliable, why are they blamed for so much that goes wrong with modern life? Who among us has not been the victim of an erroneous credit report, or a bill sent to the wrong address, or been put on hold for a long time because "the computer is down"? The answer is fairly simple: It's almost certainly not the computer. More precisely, it's very unlikely that the CPU was at fault; it may be the software, other equipment such as telephone lines, tape or disk drives, or any of the myriad "peripheral devices" that the computer uses to store and retrieve information and interact with the outside world. Usually, it's the software; when customer service representatives tell you that they can't do something obviously reasonable, you can count on its being the software. For example, I once belonged to a 401K plan whose administrators provided statements only every three months, about three months after the end of the quarter; in other words, in July I found out how much my account had been worth at the end of March. The only way to estimate how much I had in the meantime was to look up the share values in the newspaper and multiply by the number of shares. Of course, the mutual fund that issued the shares could tell its shareholders their account balances at any time of the day or night; however, the company that administered the 401K plan didn't bother to provide such a service, as it would have required doing some work.3 Needless to say, whenever I hear that "the computer can't do that" as an excuse for such poor service, I reply "Then you need some different programmers."

Nonnumeric Variables

All of this emphasis on computation, however, should not blind us to the fact that computers are not solely arithmetic engines. The most common application for which PCs are used is Web browsing, hardly a hotbed of arithmetical calculation. While we have so far considered only numeric data, this is a good illustration of the fact that computers also deal with another kind of information, which is commonly referred to by the imaginative term nonnumeric variables. Numeric variables are those suited for use in calculations, such as in totalling a set of weights. On the other hand, nonnumeric data are items that are not used in calculations like adding, multiplying, or subtracting: Examples are names, addresses, telephone numbers, Social Security numbers, bank account numbers, or driver's license numbers. Note that just because something is called a number, or even is composed entirely of the digits 0-9, does not make it numeric data by our standards; the question is how the item is used. No one adds, multiplies, or subtracts driver's license numbers, for example; they serve solely as identifiers and could just as easily have letters in them, as indeed some do.

For the present, though, let's stick with numeric variables. Now that we have defined a couple of types of these variables, short and unsigned short, what can we do with them? To do anything with them, we have to write a C++ program, which consists primarily of a list of operations to be performed by the computer, along with directions that influence how these operations are to be translated into machine instructions.

This raises an interesting point: Why does our C++ program have to be translated into machine instructions? Isn't it the computer's job to execute (or run) our program?

3.4. The Compiler

Yes, but it can't run a C++ program. The only kind of program any computer can run is one made of machine instructions; this is called a machine language program, for obvious reasons. Therefore, to get our C++ program to run, we have to translate it into a machine language program. Don't worry, you won't have to do this yourself; that's why we have a program called a compiler.4 The most basic tasks that the compiler performs are the following:
1. Assigning memory addresses to variables. This allows us to use names for variables, rather than having to keep track of the address of each variable ourselves.
2. Translating arithmetic and other operations (such as +, -, etc.) into the equivalent machine instructions, including the addresses of variables assigned in the previous step.5
This is probably a bit too abstract to be easily grasped, so let's look at an example as soon as we have defined some terms. Each complete operation understood by the compiler is called a statement, and ends with a semicolon (;).6 Figure 3.1 shows some sample statements that do arithmetic calculations.7
FIGURE 3.1. A little numeric calculation
short i;
short j;
short k;
short m;

i = 5;
j = i * 3; // j is now 15
k = j - i; // k is now 10
m = (k + j) / 5; // m is now 5
i = i + 1; // i is now 6
To enter such statements in the first place, you can use any text editor that generates "plain" text files, such as the EDIT program that comes with DOS or the Notepad program in Windows. Whichever text editor you use, make sure that it produces files that contain only what you type; stay away from programs like Windows Write or Word for Windows, as they add some of their own information to indicate fonts, type sizes, and the like, to your file, which will foul up the compiler.

Since we're already on the subject of files, this would be a good time to point out that the two main types of files in C++ are implementation files (also known as source files), which in our case have the extension .cpp, and header files, which by convention have the extension .h.8 Implementation files contain statements that result in executable code, while each header file contains information that allows us to access a set of language features.

Once we have entered the statements for our program, we use the compiler to translate the programs we write into a form that the computer can perform. As defined in Chapter 1, the form we create is called source code, since it is the source of the program logic, while the form of our program that the computer can execute is called an executable program, or just an executable for short.

As I've mentioned before, there are several types of variables, the short being only one of these types. Therefore, the compiler needs some explanatory material so that it can tell what types of variables you're using; that's what the first four lines of our little sample program fragment are for. Each line tells the compiler that the type of the variable i, j, k, or m is short; that is, it can contain values from - 32768 to +32767.9

After this introductory material, we move into the list of operations to be performed. This is called the executable portion of the program, as it actually causes the computer to do something when the program is executed; the operations to be performed, as mentioned above, are called statements. The first one, i = 5;, sets the variable i to the value 5. A value such as 5, which doesn't have a name, but represents itself in a literal manner, is called (appropriately enough) a literal value.

This is as good a time as any for me to mention something that experienced C++ programmers take for granted, but which has a tendency to confuse novices. This is the choice of the = sign to indicate the operation of setting a variable to a value, which is known technically as assignment. As far as I'm concerned, an assignment operation would be more properly indicated by some symbol suggesting movement of data, such as 5 => i;, meaning "store the value 5 into variable i". Unfortunately, it's too late to change the notation for the assignment statement, as such a statement is called, so you'll just have to get used to it. The = means "set the variable on the left to the value on the right".10

Now that I've warned you about that possible confusion, let's continue looking at the operations in the program. The next one, j = i * 3;, specifies that the variable j is to be set to the result of multiplying the current value of i by the literal value 3. The one after that, k = j - i;, tells the computer to set k to the amount by which j is greater than i; that is, j - i. The most complicated line in our little program fragment, m = (k + j) / 5;, calculates m as the sum of adding k and j and dividing the result by the literal value 5. Finally, the line i = i + 1; sets i to the value of i plus the literal value 1.

This last statement may be somewhat puzzling; how can i be equal to i + 1? The answer is that an assignment statement is not an algebraic equality, no matter how much it may resemble one. It is a command telling the computer to assign a value to a variable. Therefore, what i = i + 1; actually means is "Take the current value of i, add 1 to it, and store the result back into i." In other words, a C++ variable is a place to store a value; the variable i can take on any number of values, but only one at a time; any former value is lost when a new one is assigned.

This notion of assignment was the topic of quite a few messages with Susan. Let's go to the first round:

Susan: I am confused with the statement i = i + 1; when you have stated previously that i = 5;. So, which one is it? How can there be two values for i?
Steve: There can't; that is, not at one time. However, i, like any other variable, can take on any number of values, one after another. First, we set it to 5; then we set it to 1 more than it was before (i + 1), so it ends up as 6.
Susan: Well, the example made it look as if the two values of i were available to be used by the computer at the same time. They were both lumped together as executable material.
Steve: After the statement i = 5;, and before the statement i = i + 1;, the value of i is 5. After the statement i = i + 1;, the value of i is 6. The key here is that a variable such as i is just our name for some area of memory that can hold only one value at one time. Does that clear it up?
Susan: So, it is not like algebra? Then i is equal to an address of memory and does not really equate with a numerical value? Well, I guess it does when you assign a numerical value to it. Is that it?
Steve: Very close. A variable in C++ isn't really like an algebraic variable, which has a value that has to be figured out and doesn't change in a given problem. A programming language variable is just a name for a storage location that can contain a value.
With any luck, that point has been pounded into the ground, so you won't have the same trouble that Susan did. Now let's look at exactly what an assignment statement does. If the value of i before the statement i = i + 1; is 5 (for example), then that statement will cause the CPU to perform the following steps:11
1. Take the current value of i (5).
2. Add one to that value (6).
3. Store the result back into i.
After the execution of this statement, i will have the value 6.

3.5. How the CPU Stores and Manipulates Data in Memory

In a moment we're going to dive a little deeper into how the CPU accomplishes its task of manipulating data, such as we are doing here with our arithmetic program. First, though, it's time for a little pep talk for those of you who might be wondering exactly why this apparent digression is necessary. It's because if you don't understand what is going on under the surface, you won't be able to get past the "Sunday driver" stage of programming in C++. In some languages it's neither necessary nor perhaps even possible to find out what the computer actually does to execute your program, but C++ isn't one of them. A good C++ programmer needs an intimate acquaintance with the internal workings of the language, for reasons which will become very apparent when we get to Chapter 6. For the moment, you'll just have to take my word that working through these intricacies is essential; the payoff for a thorough grounding in these fundamental concepts of computing will be worth the struggle.

Now let's get to the task of exploring how the CPU actually stores and manipulates data in memory. As we saw previously, each memory location in RAM has a unique memory address; machine instructions that refer to RAM use this address to specify which byte or bytes of memory they wish to retrieve or modify. This is fairly straightforward in the case of a 1-byte variable, where the instruction merely specifies the byte that corresponds to the variable. On the other hand, the situation isn't quite as simple in the case of a variable that occupies more than 1 byte. Of course, no law of nature says that an instruction couldn't contain a number of addresses, one for each byte of the variable. However, this solution is never adopted in practice, as it would make instructions much longer than they need to be. Instead, the address in such an instruction specifies the first byte of RAM occupied by the variable, and the other bytes are assumed to follow immediately after the first one. For example, in the case of a short variable, which as we have seen occupies 2 bytes of RAM, the instruction would specify the address of the first byte of the area of RAM in which the variable is stored.12 However, there's one point that I haven't brought up yet: how the data for a given variable are actually arranged in memory. For example, suppose that the contents of a small section of RAM (specified as two hex digits per byte) look like Figure 3.2.

FIGURE 3.2. A small section of RAM

Address Hex byte value

1000 41

1001 42

1002 43

1003 44

1004 00

Also suppose that a short variable i is stored starting at address 1000. To do much with a variable, we're going to have to load it into a general register, one of the small number of named data storage locations in the CPU intended for general use by the programmer; this proximity allows the CPU to operate on data in the registers at maximum speed. You may recall that there are seven general registers in the 386 CPU (and its successors); they're named eax, ebx, ecx, edx, esi, edi, and ebp.13 Unfortunately, there's another complication here; these registers are designed to operate on 4-byte quantities, while our variable i, being of type short, is only two bytes long. Are we out of luck? No, but we do have to specify how long the variable is that we want to load. This problem is not unique to Intel CPUs, since any CPU has to have the ability to load different-sized variables into registers. Different CPUs use different methods of specifying this important piece of information; in the Intel CPUs, one way to do this is to alter the register name.14 As we saw in the discussion of the development of Intel machines, we can remove the leading e from the register name to specify that we're dealing with 2-byte values; the resulting name refers to the lower two bytes of the 4-byte register. Therefore, if we wanted to load the value of i into register ax (that is, the lower half of register eax), the instruction could be written as follows:15

mov ax,[1000]16

As usual, our resident novice Susan had some questions on this topic. Here is our conversation:
Susan: If you put something into 1000 that is "too big" for it, then it spills over to the next address?
Steve: Sort of. When you "put something into 1000" , you have to specify exactly what it is you're "putting in". That is, it must be either a short, a char, or some other type of variable that has a defined size.
Susan: Is that how it works? Why then is it not necessary to specify that it is going to have to go into 1000 and 1001? So what you put in is not really in 1000 anymore, it is in 1000 and 1001? How do you refer to its REAL address? What if there is no room in 1001? Would it go to 2003 if that is the next available space?
Steve: Because the rule is that you always specify the starting address of any item (variable or constant) that is too big to fit in 1 byte. The other bytes of the item are always stored immediately following the address you specify. No bytes will be skipped when storing (or loading) one item; if the item needs 4 bytes and is to be stored starting at 1000, it will be stored in 1000-1003.
Susan: I see. In other words, the compiler will always use the next bytes of RAM, however many need to be used to store the item?
Steve: Right.

3.6. The Layout of Data in Memory

Now I have a question for you. After we execute the assembly language statement mov ax,[1000] to load the value of i into ax, what's in register ax? Of course; the answer is the value of i, but what is that value? The first byte of i, at location 1000, has the value 41 hexadecimal (abbreviated 41h), and the second byte, at location 1001, has the value 42h. But the value of i is 2 bytes long; is it 4142h or 4241h? These are clearly not the same!

That was a trick question; there's no way for you to deduce the answer with only the information I've given you so far. The answer happens to be 4241h, because that's the way Intel decided to do it; that is, the low part of the value is stored in the byte of RAM where the variable starts. Some other CPUs, e.g., Motorola's 680x0 series, do it the opposite way, where the high part of the value is stored in the byte of RAM where the variable starts; this is called big-endian, since the big end of the value is first, while the Intel way is correspondingly called little-endian. And some machines can use either of these methods according to how they are started up. This makes it easier for them to run software written for either memory orientation.

As you might have surmised, the same system applies to 4-byte values. Therefore, since we're on a little-endian machine, if we wrote the instruction mov eax,[1000], it would load the eax register with the value 44434241h; that is, the four bytes 41, 42, 43, and 44 (hex) would be loaded into the eax register, with the byte having the lowest address loaded into the low end of the register.

Here's another example. A little-endian system would represent the number 1234 (hex) stored at address 5000 as in Figure 3.3, whereas a big-endian system would represent the same value 1234 (hex) as illustrated in Figure 3.4.

FIGURE 3.3. One little endian value

Address Value

5000 34

5001 12

FIGURE 3.4. A big endian example

Address Value

5000 12

5001 34

This really isn't much of a problem as long as we don't try to move data from one type of machine to another; however, when such data transportation is necessary, dealing with mixed endianness can be a real nuisance.17 Before going on, let's practice a bit with this notion of how data are stored in memory.

3.7. Exercises, First Set

1. Assume that a short variable named z starts at location 1001 in a little-endian machine. Using Figure 3.5 for the contents of memory, what is the value of z, in hex?
FIGURE 3.5. Exercise 1

Address Hex byte value

1000 3a

1001 43

1002 3c

1003 99

1004 00

Playing Compiler

I can almost hear the wailing and tooth gnashing out there. Do I expect you to deal with these instructions and addresses by yourself? You'll undoubtedly be happy to know that this isn't necessary, as the compiler takes care of these details. However, if you don't have some idea of how a compiler works, you'll be at a disadvantage when you're trying to figure out how to make it do what you want. Therefore, we're going to spend the next few pages "playing compiler"; that is, I'll examine each statement in a small program fragment and indicate what action the compiler might take as a result. I'll simplify the statements a bit to make the explanation simpler; you should still get the idea. Figure 3.6 illustrates the set of statements that I'll compile:18
FIGURE 3.6. A really little numeric calculation
short i;
short j;

i = 5;
j = i + 3;
Here are the rules of this game:
1. All numbers in the C++ program are decimal; all addresses and numbers in the machine instructions are hexadecimal.19
2. All addresses are 2 bytes long.20
3. Variables are stored at addresses starting at 1000.
4. Machine instructions are stored at addresses starting at 2000.21
5. A number not enclosed in [] is a literal value, which represents itself. For example, the instruction mov ax,1000 means to move the value 1000 into the ax register.
6. A number enclosed in [] is an address, which specifies where data are to be stored or retrieved. For example, the instruction mov ax,[1000] means to move 2 bytes of data starting at location 1000, not the value 1000 itself, into the ax register.
7. All the data values are shown as "?? ??" to indicate that the variables have not had values assigned to them yet.
Now let's start compiling. The first statement, short i; says to allocate storage for a 2-byte variable called i that will be treated as signed (because that's the default). Since no value has been assigned to this variable yet, the resulting "memory map" looks like Figure 3.7.
FIGURE 3.7. Compiling, part 1
Address
Variable Name
Value
1000
i
?? ??

As you might have guessed, this exercise was the topic of a considerable amount of discussion with Susan. Here's how it started:
Susan: So the first thing we do with a variable is to tell the address that its name is i, but no one is home, right? It has to get ready to accept a value. Could you put a value in it without naming it, just saying address 1000 has a value of 5? Why does it have to be called i first?
Steve: The reason that we use names instead of addresses is because it's much easier for people to keep track of names than it is to keep track of addresses. Thus, one of the main functions of a compiler is to allow us to use names that are translated into addresses for the computer's use.
The second statement, short j; tells me to allocate storage for a 2-byte variable called j that will be treated as signed (because that's the default). Since no value has been assigned to this variable yet, the resulting "memory map" looks like Figure 3.8.
FIGURE 3.8. Compiling, part 2
Address
Variable Name
Value
1000
i
?? ??
1002
j
?? ??

Here's the exchange about this step:

Susan: Why isn't the address for j 1001?
Steve: Because a short is 2 bytes, not 1. Therefore, if i is at address 1000, j can't start before 1002; otherwise, the second byte of i would have the same address as the first byte of j, which would cause chaos in the program. Imagine changing i and having j change by itself!
Susan: Okay. I just thought that each address represented 2 bytes for some reason. Then in reality each address always has just 1 byte?
Steve: Every byte of RAM has a distinct address, and there is one address for each byte of RAM. However, it is often necessary to read or write more than one byte at a time, as in the case of a short, which is 2 bytes in length. The machine instructions that read or write more than 1 byte specify only the address of the first byte of the item to be read or written; the other byte or bytes of that item follow the first byte immediately in memory.
Susan: Okay, this is why I was confused. I thought when you specified that the RAM address 1000 was a short (2 bytes), it just made room for 2 bytes. So when you specify address 1000 as a short, you know that 1001 will also be occupied with what you put in 1000.
Steve: Or to be more precise, location 1001 will contain the second byte of the short value that starts in byte 1000.
The next line is blank, so we skip it. This brings us to the statement i = 5; which is an executable statement, so we need to generate one or more machine instructions to execute it. We have already assigned address 1000 to i, so we have to generate instructions that will set the 2 bytes starting at address 1000 to the value that represents 5. One way to do this is to start by setting ax to 5, by the instruction mov ax,5, then storing the contents of ax (5, of course) into the two-byte location where the value of i is kept, namely the two bytes starting at address 1000, via the instruction mov [1000],ax.

Figure 3.9 shows what our "memory map" looks like so far.

FIGURE 3.9. Compiling, part 3
Address
Variable Name
Value
1000
i
?? ??
1002
j
?? ??
Address
Machine Instruction
Assembly Language Equivalent
2000
b8 05 00
mov ax, 5
2003
a9 00 10
mov [1000],ax

Here's the next installment of my discussion with Susan on this topic:
Susan: When you use ax in an instruction, that is a register, not RAM?
Steve: Yes.
Susan: How do you know you want that register and not another one? What are the differences in the registers? Is ax the first register that data will go into?
Steve: For our current purposes, all of the 16-bit general registers (ax, bx, cx, dx, si, di, bp) are the same. Some of them have other uses, but all of them can be used for simple arithmetic such as we're doing here.
Susan: How do you know that you are not overwriting something more important than what you are presently writing?
Steve: In assembly language, the programmer has to keep track of that; in the case of a compiled language, the compiler takes care of register allocation for you, which is another reason to use a compiler rather than writing assembly language programs yourself.
Susan: If it overwrites, you said important data will go somewhere else. How will you know where it went? How does it know whether what is being overwritten is important? Wait. If something is overwritten, it isn't gone, is it? It is just moved, right?
Steve: The automatic movement of data that you're referring to applies only to cached data being transferred to RAM. That is, if a slot in the cache is needed, the data that it previously held is written out to RAM without the programmer's intervention. However, the content of registers is explicitly controlled by the programmer (or the compiler, in the case of a compiled language). If you write something into a register, whatever was there before is gone. So don't do that if you need the previous contents!
Susan: OK. Now I have another question: How do you know that the value 5 will require 2 bytes?
Steve: In C++, because it's a short. In assembly language, because I'm loading it into ax, which is a 2-byte register.
Susan: That makes sense. Now why do the variable addresses start at 1000 and the machine addresses start at 2000?
Steve: It's arbitrary; I picked those numbers out of the air. In a real program, the compiler decides where to put things.
Susan: What do you mean by machine address? What is the machine? Where are the machine addresses?
Steve: A machine address is a RAM address. The machine is the CPU. Machine addresses are stored in the instructions so the CPU knows which RAM location we're referring to.
Susan: We talked about storing instructions before; is this what we are doing here? Are those instructions the "machine instructions"?
Steve: Yes.
Susan: Now, this may sound like a very dumb question, but please tell me where 5 comes from? I mean if you are going to move the value of 5 into the register ax, where is 5 hiding to take it from and to put it in ax? Is it stored somewhere in memory that has to be moved, or is it simply a function of the user just typing in that value?
Steve: It is stored in the instruction as a literal value. If you look at the assembly language illustration on page 86, you will see that the mov ax,5 instruction translates into the three bytes b8 05 00; the 05 00 is the 5 in "little-endian" notation.
Susan: Now, what is so magical about ax (or any register for that matter) that will transform the address 1000 to hold the value of 5?
Steve: The register doesn't do it; the execution of the instruction mov [1000],ax is what sets the memory starting at address 1000 to the value 5.
Susan: What are those numbers supposed to be in the machine instruction box? Those are bytes? Bytes of what? Why are they there? What do they do?
Steve: They represent the actual machine language program as it is executed by the CPU. This is where "the rubber meets the road". All of our C++ or even assembly language programs have to be translated into machine language before they can be executed by the CPU.
Susan: So this is where 5 comes from? I can't believe that there seems to be more code. What is b8 supposed to be? Is it some other type of machine language?
Steve: Machine language is exactly what it is. The first byte of each instruction is the "operation code", or "op code" for short. That tells the CPU what kind of instruction to execute; in this case, b8 specifies a "load register ax with a literal value" instruction. The literal value is the next 2 bytes, which represent the value 5 in "little-endian" notation; therefore, the full translation of the instruction is "load ax with the literal value 5".
Susan: So that is the "op code"? Okay, this makes sense. I don't like it, but it makes sense. Will the machine instructions always start with an op code?
Steve: Yes, there's always an op code first; that's what tells the CPU what the rest of the bytes in the instruction mean.
Susan: Then I noticed that the remaining bytes seem to hold either a literal value or a variable address. Are those the only possibilities?
Steve: Those are the ones that we will need to concern ourselves with.
Susan: I don't understand why machine addresses aren't in 2-byte increments like variable addresses.
Steve: Variable addresses aren't always in 2-byte increments either; it just happens that short variables take up 2 bytes. Other kinds of variables can and often do have other lengths.
Susan: So even though variable addresses are the same as instruction addresses they really aren't because they can't share the same actual address. That is why you distinguish the two by starting the instruction addresses at 2000 in the example and variable addresses at 1000, right?
Steve: Right. A particular memory location can hold only one data item at a time. As far as RAM is concerned, machine instructions are just another kind of data. If a particular location is used to store one data item, you can't store anything else there at the same time, whether it's instructions or data.
The last statement, j = i + 3; is the most complicated statement in our program, and it's not that complicated. As with the previous statement, it's executable, which means we need to generate machine instructions to execute it. Because we haven't changed ax since we used it to initialize the variable i with the value 5, it still has that value. Therefore, to calculate the value of j, we can just add 3 to the value in ax by executing the instruction add ax,3. After the execution of this instruction, ax will contain i + 3. Now all we have to do is to store that value in j. As indicated in the translation of the statement short j; the address used to hold the value of j is 1002. Therefore, we can set j to the value in ax by executing the instruction mov [1002],ax.

By the way, don't be misled by this example into thinking that all machine language instructions are 3 bytes in length. It's just a coincidence that all of the ones I've used here are of that length. The actual size of an instruction on the Intel CPUs can vary considerably, from 1 byte to a theoretical maximum of 12 bytes. Most instructions in common use, however, range from 1 to 5 bytes.

Figure 3.10 shows what the "memory map" looks like now.

FIGURE 3.10. Compiling, part 4
Address
Variable Name
Value
1000
i
?? ??
1002
j
?? ??
Address
Machine Instruction
Assembly Language Equivalent
2000
b8 05 00
mov ax, 5
2003
a9 00 10
mov [1000],ax
2006
05 03 00
add ax,3
2009
a9 02 10
mov [1002],ax

Here's the rest of the discussion that we had about this little exercise:
Susan: In this case mov means add, right?
Steve: No, mov means "move" and add means "add". When we write mov ax,5, it means "move the value 5 into the ax register". The instruction add ax,3 means "add 3 to the current contents of ax, replacing the old contents with this new value".
Susan: So you're moving 5 but adding 3? How do you know when to use mov and when to use add if they both kind of mean the same thing?
Steve: It depends on whether you want to replace the contents of a register without reference to whatever the contents were before (mov) or add something to the contents of the register (add).
Susan: OK, here is what gets me: how do you get from address 1000 and i=5 to ax? No, that's not it; I want you to tell me what is the relationship between ax and address 1000. I see ax as a register and that should contain the addresses, but here you are adding ax to the address. This doesn't make sense to me. Where are these places? Is address 1000 in RAM?
Steve: The ax register doesn't contain an address. It contains data. After the instruction mov ax,5, ax contains the number 5. After the instruction mov [1000],ax, memory location 1000 contains a copy of the 2-byte value in register ax; in this case, that is the value of the short variable i.
Susan: So do the machine addresses represent actual bytes?
Steve: The machine addresses specify the RAM locations where data (and programs) are stored.

Executing Our Little Program Fragment

Having examined what the compiler does at compile time with the preceding little program fragment, let's see what happens when the compiled program is executed at run time. When we start out, the sections of RAM we're concerned with will look like Figure 3.11; in each of these figures, the italic text indicates the next instruction to be executed.Now let's start executing the program. The first instruction, mov ax,5, as we saw earlier, means "set the contents of ax to the value 5".

Figure 3.12 shows the situation after mov ax,5 is executed. As you can see, executing mov ax,5 has updated the contents of ax, and we've advanced to the next instruction, mov [1000],ax. When we have executed that instruction, the situation looks like Figure 3.13, with the variable i set to 5. Figure 3.14 shows the result after the following instruction, add ax,3, is executed.

FIGURE 3.11. Before execution

Address
Variable Name
Contents
1000
i
?? ??
1002
j
?? ??
--
ax
?? ??
Address
Machine Instruction
Assembly Language Equivalent
2000
b8 05 00
mov ax, 5
2003
a9 00 10
mov [1000],ax
2006
05 03 00
add ax,3
2009
a9 02 10
mov [1002],ax

FIGURE 3.12. After the first instruction is executed

Address
Variable Name
Contents
1000
i
?? ??
1002
j
?? ??
--
ax
5
Address
Machine Instruction
Assembly Language Equivalent
2000
b8 05 00
mov ax, 5
2003
a9 00 10
mov [1000],ax
2006
05 03 00
add ax,3
2009
a9 02 10
mov [1002],ax

FIGURE 3.13. After execution of second instruction

Address
Variable Name
Contents
1000
i
5
1002
j
?? ??
--
ax
5
Address
Machine Instruction
Assembly Language Equivalent
2000
b8 05 00
mov ax, 5
2003
a9 00 10
mov [1000],ax
2006
05 03 00
add ax,3
2009
a9 02 10
mov [1002],ax

FIGURE 3.14. After execution of third instruction

Address
Variable Name
Contents
1000
i
5
1002
j
?? ??
--
ax
8
Address
Machine Instruction
Assembly Language Equivalent
2000
b8 05 00
mov ax, 5
2003
a9 00 10
mov [1000],ax
2006
05 03 00
add ax,3
2009
a9 02 10
mov [1002],ax

As expected, add ax,3 has increased the contents of ax by the value 3, producing 8. Now we're ready for the final instruction.
FIGURE 3.15. After execution of final instruction

Address
Variable Name
Contents
1000
i
5
1002
j
8
--
ax
8
Address
Machine Instruction
Assembly Language Equivalent
2000
b8 05 00
mov ax, 5
2003
a9 00 10
mov [1000],ax
2006
05 03 00
add ax,3
2009
a9 02 10
mov [1002],ax

Figure 3.15 shows the situation after the final instruction, mov [1002],ax, has been executed.

After executing the final instruction, mov [1002],ax, the variable i has the value 5 and the variable j has the value 8.

3.8. The char and string Types

This should give you some idea of how numeric variables and values work. But what about nonnumeric ones?

This brings us to the subject of two new variable types and the values they can contain. These are the char (short for "character") and its relative, the string. What are these good for, and how do they work?22

A variable of type char corresponds to 1 byte of storage. Since a byte has 8 bits, it can hold any of 256 (28) values; the exact values depend on whether it is signed or unsigned, as with the short variables we have seen before.23 Going strictly according to this description, you might get the idea that a char is just a "really short" numeric variable. A char indeed can be used for this purpose in cases where no more than 256 different numeric values are to be represented. In fact, this explains why you might want a signed char. Such a variable can be used to hold numbers from -128 to +127; an unsigned char, on the other hand, has a range from 0 to 255. This facility isn't used very much any more, but in the early days of C, memory was very expensive and scarce, so it was sometimes worth the effort to use 1-byte variables to hold small values.

However, the main purpose of a char is to represent an individual letter, digit, punctuation mark, "special character" (e.g., $, @, #, %, and so on) or one of the other "printable" and displayable units from which words, sentences, and other textual data such as this paragraph are composed.24

These 256 different possibilities are plenty to represent any character in English, as well as a number of other European languages. But the written forms of "ideographic" languages, such as Chinese, consist of far more than 256 characters, so 1 byte isn't big enough to hold a character in these languages. While they have been supported to some extent by schemes that switch among a number of sets of 256 characters each, such clumsy approaches to the problem made programs much more complicated and error prone. As the international market for software is increasing rapidly, it has become more important to have a convenient method of handling large character sets; as a result, a standard method of representing the characters of such languages by using 2 bytes per character has been developed. It's called the "Unicode standard". There's even a proposed solution that uses 32 bits per character, for the day when Unicode doesn't have sufficient capacity.

Since one char isn't good for much by itself, we often use groups of them, called strings, to make them easier to handle. Just as with numeric values, these variables can be set to literal values which represent themselves. Figure 3.16 is an example of how to specify and use each of these types we've just encountered. This is the first complete program we've seen, so there are a couple of new constructs that I'll have to explain to you.

By the way, in case the program in Figure 3.16 doesn't seem very useful, that's because it isn't; it's just an example of the syntax of defining and using variables and literal values. However, we'll use these constructs to do useful work later, so going over them now isn't a waste of time.

FIGURE 3.16. Some real characters and strings (code\basic00.cpp)

#include <string>

using namespace std;

int main()

{

char c1;

char c2;

string s1;

string s2;

c1 = `A';

c2 = c1;

s1 = "This is a test ";

s2 = "and so is this.";

return 0;

}

Why do we need the line #include <string>? Because we have to tell the compiler that we want to manipulate strings; the code that allows us to do that isn't automatically included with our programs unless we ask for it. For the moment, it's enough to know that including <string> is necessary to tell the compiler that we want to use strings; we'll get into some details of this mechanism later.

3.9. using, namespace, and std

The next line, using namespace std;, will be present in nearly all of our programs. It tells the compiler to treat the names in the standard library, a very important part of the C++ language definition, as though we had defined them in the current program. These names from the standard library include string, which is why we need using namespace std; here. I'll go into this in much more detail later, but in the meantime, here's a little information about using, namespace, and std.

A namespace is a collection of identifiers (variable names and some other types of names that we haven't discussed yet) that all belong to a "family" of sorts. To refer to a specific identifier that belongs to a namespace, you can prefix the identifier with the name of the namespace followed by two colons.

For example, all of the identifiers in the C++ standard library are in the namespace called std. So, for example, if we want to refer to the version of string that is in the namespace called std, we can refer to it by the name std::string.

However, because the standard library identifiers are used so frequently, it is annoying to have to say std:: every time we want to refer to one of them. The designers of the language have anticipated this problem and have provided the using facility to allow us to write our programs in a more natural way. What using means is that we want the compiler to add a certain name or set of names from a particular namespace to the currently accessible set of names. In this particular case, using namespace std; means that we want the compiler to make all the names in the standard library accessible. If we left that line out, whenever we wanted to create a variable of string type, we would have to write std::string rather than just string, and the same would be true of the other types defined in the standard library that we will be using later. I think we have enough details to keep track of without having to worry about that particular one, so I have included the line using namespace std; in all of the example programs except where I have a specific reason not to do so; I'll note those cases when we get to them.

As you can probably imagine, Susan wasn't entirely satisfied with this explanation, even for the time being. Here's the discussion we had about it:

Susan: I am not sure I understand this. In other words you just say using namespace std; and then every variable you use is going to be from the standard library?
Steve: Not quite. When we say using namespace std;, that means "add the names from the standard library to the names we have available for use". For example, after that statement, if I say cout, I mean std::cout, and if I say string, I mean std::string. Names not defined in the standard library aren't affected by this.
Susan: Isn't that what I said? My question is, if you don't want to use the standard library, how do you indicate that?
Steve: No, what you said is that "every" variable is from the standard library. It's only things that have names defined in the standard library that are affected. However, if you have something called "string", for example, that is defined in the standard library and also in your code, you can say "::string" if you don't want to use the one from the standard library. We'll see an example of this in "The Scope Resolution Operator" on page 273 in Chapter 5.
Susan: Okay.

3.10. int main()

The next construct we have to examine is the line int main(), which has two new components. The first is the "return type", which specifies the type of value that will be returned from the program when it ends. In this case, that type is int, which is an integral type exactly like short, except that its size depends on the compiler that you're using.25 With the 32-bit compiler on the CD in this book, an int is 32 bits, or twice the size of a short. With a 16-bit compiler such as Borland C++ version 3.1, an int is the same size as a short, whereas on a 64-bit compiler an int would be 64 bits in length. I don't like to use ints where a short will do, because I want to minimize the changes in behavior of my code with compilers that use different word lengths. While it's true that there isn't much new development that uses 16-bit compilers anymore, it is also true that one of these days we'll all probably be using 64-bit compilers, and I would like my code to be as portable to them as possible.26 However, we don't have much choice here, because the C++ language specifies that main has to have the return type int.

This brings us to the meaning of main(). This tells the compiler where to start executing the code: C++ has a rule that execution always starts at the place called main.27

We'll get into this in more detail later in this chapter and in Chapter 5. For now, you'll just have to take my word that this is necessary; I promise I'll explain what it really means when you have enough background to understand the explanation.

There's one more construct I should tell you about here: the curly braces, { and }. The first one of these starts a section of code, in this case the code that belongs to main, and the second one ends that section of code. This is needed because otherwise the compiler wouldn't be able to tell where the code for main begins and ends. The curly braces also have other uses, one of which we'll get to later in this chapter.28

You may also be puzzled by the function of the other statements in this program. If so, you're not alone. Let's see the discussion that Susan and I had about that topic.

Susan: Okay, in the example why did you have to write c2 = c1;? Why not B? Why make one thing the same thing as the other? Make it different. Why would you even want c2=c1; and not just say c1 twice, if that is what you want?
Steve: It's very hard to think up examples that are both simple enough to explain and realistic enough to make sense. You're right that this example doesn't do anything useful; I'm just trying to introduce what both the char type and the string type look like.
Susan: Also, do the names of the variables mean anything? Do the c in c1 and the s in s1 stand for anything?
Steve: Yes, the c and s stand for "char" and "string", respectively.
Susan: Okay, that makes more sense now. But come to think of it, what does c1='A'; have to do with the statement s1= "This is a test ";? I don't see any relationship between one thing and the other.
Steve: This is the same problem as the last one. They have nothing to do with one another; I'm using an admittedly contrived example to show how these variables are used.
Susan: I am glad now that your example of chars and strings (put together) didn't make sense to me. That is progress; it wasn't supposed to.
What does this useless but hopefully instructive program do? As is always the case, we have to tell the compiler what the types of our variables are before we can use them. In this case, c1 and c2 are of type char, whereas s1 and s2 are strings. After taking care of these formalities, we can start to use the variables. In the first executable statement, c1 = 'A'; we set the char variable c1 to a literal value, in this case a capital A; we need to surround this with single quotation marks (') to tell the compiler that we mean the letter A rather than a variable named A. In the next line, c2 = c1; we set c2 to the same value as c1 , which of course is 'A' in this case. The next executable statement s1 = "This is a test "; as you might expect, sets the string variable s1 to the value "This is a test ",29 which is a literal of a type called a C string literal. Don't confuse a C string literal with a string. A C string literal is a type of literal that we use to assign values to variables of type string. In the statement s1 = "This is a test "; we use a quotation mark, in this case the double quote ("), to tell the compiler where the literal value starts and ends.

You may be wondering why we need two different kinds of quotes in these two cases. The reason is that there are actually two types of nonnumeric data, fixed-length data and variable-length data. Fixed-length data are relatively easy to handle in a program, as the compiler can set aside the correct amount of space in advance. Variables of type char are 1 byte long and can thus contain exactly one character; as a result, when we set a char to a literal value, as we do in the line c1 = 'A'; the code that executes that statement has the simple task of copying exactly 1 byte representing the literal 'A' to the address reserved for variable c1.30

However, C string literals such as "This is a test " are variable-length data, and dealing with such data isn't so easy. Since there could be any number of characters in a C string literal, the code that does the assignment of a literal value like "This is a test " to a string variable has to have some way to tell where the literal value ends. One possible way to provide this needed information would be for the compiler to store the length of the C string literal in memory somewhere, possibly in the location immediately before the first character in the literal. I would prefer this method; however, it is not the method used in the C language (and its descendant, the C++ language). To be fair, the inventors of C didn't make an arbitrary choice; they had reasons for their decision on how to indicate the length of a string. You see, if we were to reserve only 1 byte to store the actual length in bytes of the character data in the string, then the maximum length of a string would be limited to 255 bytes. This is because the maximum value that could be stored in the length byte, as in any other byte, is 255. Thus, if we had a string longer than 255 bytes, we would not be able to store the length of the string in the 1 byte reserved for that purpose. On the other hand, if we were to reserve 2 bytes for the length of each string, then programs that contain many strings would take more memory than they otherwise would.

While the extra memory consumption that would be caused by using a 2-byte length code may not seem significant today, the situation was considerably different when C was invented. At that time, conserving memory was very important; the inventors of C therefore chose to mark the end of a C string literal by a byte containing the value 0, which is called a null byte.31 This solution has the advantage that only one extra byte is needed to indicate the end of a C string literal of any length. However, it also has some serious drawbacks. First, this solution makes it impossible to have a byte containing the value 0 in the middle of a C string literal, as all of the C string literal manipulation routines would treat that null byte as being the end of the C string literal. Second, it is a nontrivial operation to determine the length of a C string literal; the only way to do it is to scan through the C string literal until you find a null byte. As you can probably tell, I'm not particularly impressed with this mechanism; nevertheless, as it has been adopted into C++ for compatibility with C, we're stuck with it for literal strings in our programs.32 Therefore, the literal string "ABCD" would occupy 5 bytes, 1 for each character, and 1 for the null byte that the compiler adds automatically at the end of the literal. But we've skipped one step: How do we represent characters in memory? There's no intuitively obvious way to convert the character 'A' into a value that can be stored in 1 byte of memory.

The answer, at least for our purposes in English, is called the ASCII code standard. This stands for American Standard Code for Information Interchange, which as the name suggests was invented to allow the interchange of data between different programs and makes of computers. Before the invention of ASCII, such interchange was difficult or impossible, since every manufacturer made up its own code or codes. Here are the specific character codes that we have to be concerned with for the purposes of this book:

1. The codes for the capital letters start with hex 41 for 'A', and run consecutively to hex 5a for 'Z'.
2. The codes for the lower case letters start with hex 61 for 'a', and run consecutively to hex 7a for 'z'.33
3. The codes for the numeric digits start with hex 30 for '0', and run consecutively to hex 39 for '9'.
Given these rules, the memory representation of the string "ABCD" might look something like Figure 3.17.
FIGURE 3.17. Yet another small section of RAM

Address Hex byte value

1000 41

1001 42

1002 43

1003 44

1004 00 (null byte; that is, end of C string literal)

Now that we see how strings are represented in memory, I can explain why we need two kinds of quotes. The double quotes tell the compiler to add the null byte at the end of the string literal, so that when the assignment statement s1 = "This is a test "; is executed, the program knows when to stop copying the value to the string variable.

A Byte by Any Other Name...

Have you noticed that I've played a little trick here? The illustration of the string "ABCD" should look a bit familiar; its memory contents are exactly the same as in Figure 3.2, where we were discussing numeric variables. I did this to illustrate an important point: the contents of memory actually consists of uninterpreted bytes, which have meaning only when used in a particular way by a program. That is, the same bytes can represent numeric data or characters, depending on how they are referred to.

This is one of the main reasons why we need to tell the C++ compiler what types our variables have. Some languages allow variables to be used in different ways at different times, but in C++ any given variable always has the same type; for example, a char variable can't change into a short. At first glance, it seems that it would be much easier for programmers to be able to use variables any way they like; why is C++ so restrictive?

The C++ type system, as this feature of a language is called, is specifically designed to minimize the risk of misinterpreting or otherwise misusing a variable. It's entirely too easy in some languages to change the type of a variable without meaning to and the resulting errors can be very difficult to find, especially in a large program. In C++, the usage of a variable can be checked by the compiler. Such static type checking allows the compiler to tell you about many errors that otherwise would not be detected until the program is running (dynamic type checking). This is particularly important in systems that need to run continuously for long periods of time. While you can reboot your machine if your word processor crashes due to a run-time error, this is not acceptable as a solution for errors in the telephone network, for example.

Of course, you probably won't be writing programs demanding that degree of reliability any time soon, but strict static type checking is still worthwhile in helping eliminate errors at the earliest possible stage in the development of our programs.

Nonprinting Characters

After that infomercial for the advantages of static type checking, we can resume our examination of strings. You may have noticed that there's a space character at the end of the string "This is a test ". That's another reason why we have to use a special character like " (the double quote) to mark the beginning and end of a string; how else would the compiler know whether that space is supposed to be part of the string? The space character is one of the nonprinting characters (or nondisplay characters) that controls the format of our displayed or printed information; imagine how hard it would be to read this book without space characters! While we're on the subject, I should also tell you about some other characters that have special meaning to the compiler. They are listed in Figure 3.18.

I'll be more specific about the uses of parentheses later, when we have seen some examples. As for the backslash, if you wanted to (for example) insert a " in a string, you would have to use \", because just a plain " would indicate the end of the string. That is, if you wanted to display This is a "string"., you would have to write the value of the string as "This is a \"string\"."

I compiled Figure 3.18 at the instigation of guess who:

Susan: How about you line up all your cute little " ' \ ; things and just list their meanings? I forget what they are by the time I get to the next one. Your explanations of them are fine, but they are scattered all over; I want one place with all the explanations.
Steve: That's a good idea. As usual, you're doing a good job representing the novices; keep up the good work!
FIGURE 3.18. Special characters for program text
Name Graphic Purpose
Single quote
'
surrounds a single character value
Double quote " surrounds a multi-character value
Semicolon ; ends a statement
Curly braces { } groups statements together
Parentheses ( ) surrounds part of a statement
Backslash \ Tells the compiler that the next character should be treated differently from the way that it would normally be treated.

Our next task, after a little bit of practice with the memory representation of a C string literal, will be to see how we get the values of our strings to show up on the screen.

3.11. Exercises, Second Set

2. Assume that a C string literal starts at memory location 1001. If the contents of memory are as illustrated in Figure 3.19, what is the value of the C string literal?
FIGURE 3.19. A small section of RAM

Address Hex byte value

1000 44

1001 48

1002 45

1003 4c

1004 4c

1005 4f

1006 00

3.12. Input and Output

Most programs need to interact with their users, both to ask them what they want and to present the results when they are available. The computer term for this topic is I/O (short for "input/output"). We'll start by getting information from the keyboard and displaying it on the screen; later, we'll go over the more complex I/O functions that allow us to read and write data on the disk.

The program in Figure 3.20 displays the very informative text "This is a test and so is this.". The meaning of << is suggested by its arrowlike shape: The information on its right is sent to the "output target" on its left. In this case, we're sending the information to a predefined destination, cout, which stands for "character output".34 Characters sent to cout are displayed on the screen.

FIGURE 3.20. Some simple output (code\basic01.cpp)
#include <iostream>
#include <string>
using namespace std;

int main()
{
string s1;
string s2;

s1 = "This is a test ";
s2 = "and so is this.";

cout << s1;
cout << s2;

return 0;
}

This program will send the following output to the screen:

This is a test and so is this.
So much for simple output. Input from the keyboard can be just as simple. Modifying our little sample to use it results in Figure 3.21.
FIGURE 3.21. Some simple input and output (code\basic02.cpp)
#include <iostream>
#include <string>
using namespace std;

int main()
{
string s1;
string s2;

cin >> s1;
cin >> s2;

cout << s1;
cout << " ";
cout << s2;

return 0;
}

As you might have guessed, cin (shorthand for "character input") is the counterpart to cout as >> is the counterpart to <<; cin supplies characters from the keyboard to the program via the >> operator.35 This program will wait for you to type in the first string, ended by hitting the Enter key or the space bar.36 Then it will wait for you to type in the second string and hit Enter. Then the program will display the first string, followed by a blank, and then the second string.

Susan had some questions about these little programs, beginning with the question of case sensitivity:

Susan: Are the words such as cout and cin case sensitive? I had capitalized a few of them just out of habit because they begin the sentence and I am not sure if that was the reason the compiler gave me so many error messages. I think after I changed them I reduced a few messages.
Steve: Everything in C++ is case sensitive. That includes keywords like if, for, do, and so on, as well as your own variables. That is, if you have a variable called Name and another one called name, those are completely different and unrelated to one another. You have to write cin and cout just as they appear here, or the compiler won't understand you.

3.13. Changing the Course of Execution

In our examples so far, the program always executes the same statements in the same order. However, any real program is going to need to alter its behavior according to the data it is processing. For example, in a banking application, it might be necessary to send out a notice to a depositor whenever the balance in a particular account drops below a certain level; or perhaps the depositor would just be charged some exorbitant fee in that case. Either way, the program has to do something different depending on the balance. In particular, let's suppose that the "Absconders and Defaulters National Bank" has a minimum balance requirement of $10,000.37 Furthermore, let's assume that if you have less than that amount on deposit, you are charged a $20 "service charge". However, if you are foolish enough to leave that ridiculous amount of money on deposit, then they will graciously allow you to get away with not paying them while they're using your money (without paying you interest, of course). To determine whether you should be charged for your checking account, the bank can use an if statement, as shown in Figure 3.22.
FIGURE 3.22. Using an if statement (code\basic03.cpp)
#include <iostream>
using namespace std;

int main()
{
short balance;

cout << "Please enter your bank balance: ";
cin >> balance;

if (balance < 10000)
cout << "Please remit $20 service charge." << endl;
else
cout << "Have a nice day!" << endl;

return 0;
}

This program starts by displaying the line

Please enter your bank balance:
on the screen. Then it waits for you to type in your balance, followed by the Enter key (so it knows when you're done). The conditional statement checks whether you're a "good customer". If your balance is less than $10,000, the next statement is executed, which displays

Please remit $20 service charge.38

The phrase << endl is new here. It means "we're done with this line of output; send it out to the screen". You could also use the special character '\n' ("newline"), which means much the same thing.

Now let's get back to our regularly scheduled program. If the condition is false (that is, you have at least $10,000 in the bank), the computer skips the statement that asks you to remit $20; instead, it executes the one after the else, which tells you to have a nice day. That's what else is for; it specifies what to do if the condition specified in the if statement is false (that is, not true). If you typed in a number 10000 or higher, the program would display the line


Have a nice day!
You don't have to specify an else if you don't want to. In that case, if the if condition isn't true, the program just goes to the next statement as though the if had never been executed.

3.14. The while Loop

The while statement is another way of affecting the order of program execution. This conditional statement executes the statement under its control as long as a certain condition is true. Such potentially repeated execution is called a loop; a loop controlled by a while statement is called, logically enough, a while loop. Figure 3.23 is a program that uses a while loop to challenge the user to guess a secret number from 0 to 9, and keeps asking for guesses until the correct answer is entered.
FIGURE 3.23. Using a while statement (code\basic04.cpp)
#include <iostream>
using namespace std;

int main()
{
short Secret;
short Guess;

Secret = 3;

cout << "Try to guess my number. Hint: It's from 0 to 9" << endl;
cin >> Guess;

while (Guess != Secret)
{
cout << "Sorry, that's not correct." << endl;
cin >> Guess;
}

cout << "You guessed right!" << endl;

return 0;
}

There are a few wrinkles here that we haven't seen before. Although the while statement itself is fairly straightforward, the meaning of its condition, !=, isn't intuitively obvious. However, if you consider the problem we're trying to solve, you'll probably come to the (correct) conclusion that != means "not equal", since we want to keep asking for more guesses while the Guess is not equal to our Secret number.39 Since there is a comparison operator that tests for "not equal", you might wonder how to test for "equal", as well. As is explained in some detail in the next chapter, in C++ we have to use == rather than = to compare whether two values are equal.

You might also be wondering whether an if statement with an else clause would serve as well as the while; after all, if is used to select one of two alternatives, and the else could select the other one. The answer is that this would allow the user to take only one guess before the program ends; the while loop lets the user try again as many times as needed to get the right answer.

This example also illustrates another use of the curly braces, { and }. The first one of these starts a logical section of a program, called a block, and the second one ends the block. Because the two statements after the while are part of the same block, they are treated as a unit; both are executed if the condition in the while is true, and neither is executed if it is false. A block can be used anywhere that a statement can be used, and is treated in exactly the same way as if it were one statement.

Now you should have enough information to be able to write a simple program of your own. Susan asked for an assignment to do just that:

Susan: Based on what you have presented in the book so far, send me a setup, an exercise for me to try to figure out how to program, and I will give it a try. I guess that is the only way to do it. I can't even figure out a programmable situation on my own. So if you do that, I will do my best with it, and that will help teach me to think. (Can that be?) Now, if you do this, make it simple, and no tricks.
Of course, I did give her the exercise she asked for (exercise 3), but also of course, that didn't end the matter. She decided to add her own flourish, which resulted in exercise 4. These exercises follow below.

However, you'll have to install the compiler before you can write a program. To do this, follow the instructions in the readme.txt file on the CD.

Once you have followed those instructions, including successfully compiling one of the sample programs, use a text editor such as Notepad to write the source code for your program. Save the source code as myprog.cpp. Then follow the instructions in the readme.txt file on the CD to compile the source code. The resulting program will be called myprog.exe. To run your program normally from a DOS prompt, make sure you are in the "\dialog\code" directory, and then type the name of the program, without the extension. In this case, you would just type "myprog". You can also run the program under the debugger to see how it works in detail, by following the instructions in the readme.txt file on the CD.

Now here are the programs Susan came up with, along with some others that fall in the same category.

3.15. Exercises, Third Set

3. Write a program that asks the user to type in the number of people that are expected for dinner, not counting the user. Assuming that the number typed in is n, display a message that says "A table for (n+1) is ready.". For example, if the user types 3, display "A table for 4 is ready.".
4. Modify the program from exercise 3 to display an error message if the number of guests is more than 20.
5. Write a program that asks the user to type in his or her first name and age. If the age is less than 53, then indicate that the user is a youngster; otherwise, that he or she is getting on in years.
6. Write a program that asks the user whether Susan is the world's most tenacious novice. If the answer is "true", then acknowledge the user's correct answer; if the answer is "false", then indicate that the answer is erroneous. If neither "true" nor "false" is typed in, chastise the user for not following directions.
7. Write a program that calculates how much allowance a teenager can earn by doing extra chores. Her allowance is calculated as $10 if she does no extra chores; she gets $1 additional for each extra chore she does.

3.16. 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 (code\pump1.cpp)
English C++
First, we provide some typical setup information for the beginning of a program
Define the standard input and output functionality #include <iostream>

Allow standard names to be used by default using namespace std;
This is the main part of the program int main()
Execution starts here {
Define variables short CurrentWeight; short HighestWeight;
Here's the start of the executable code
Ask for the first weight cout << "Please enter the first weight: ";
Set the number in the CurrentWeight slot to the value entered by the user cin >> CurrentWeight;
Copy the number in the CurrentWeight slot to the HighestWeight slot HighestWeight = CurrentWeight;
Display the current and highest weights cout << "Current weight " << CurrentWeight << endl; cout << "Highest weight " << HighestWeight << endl;
While the number in the CurrentWeight slot is greater than 0 (i.e., there are more pumpkins to be weighed) while (CurrentWeight > 0)
Start repeated steps {
Ask for the next weight cout << "Please enter the next weight: ";
Set the number in the CurrentWeight slot to this value cin >> CurrentWeight;
If the number in the CurrentWeight slot is more than the number in the HighestWeight slot, if (CurrentWeight > HighestWeight)
then copy the number in the CurrentWeight slot to the HighestWeight slot HighestWeight = CurrentWeight;
Display the current and highest weights cout << "Current weight " << CurrentWeight << endl; cout << "Highest weight " << HighestWeight << endl;
End repeated steps in while loop }
We've finished the job; now to clean up
Tell the rest of the system we're okay return 0;
End of program }

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
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.

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.

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.

3.17. Exercises, Fourth Set

8. Here are four possible versions of an output statement. Assuming that the value of the string variable called name is "Joe Smith", what does each one of them do?

cout << "That is very old, " << name << ". " << endl;

cout << "That is very old, " << name << '. ' << endl;

cout << "That is very old, " << name << "." << endl;

cout << "That is very old, " << name << '.' << endl;
Now it's time for some review on what we've covered in this chapter.

3.18. Review

We started out by discussing the tremendous reliability of computers. Whenever you hear "it's the computer's fault", the overwhelming likelihood is that the software is to blame rather than the hardware. Then we took a look at the fact that although computers are calculating engines, many of the functions we use them for don't have much to do with numeric calculations; for example, the most common use of computers is probably Web browsing. Nevertheless, we started out our investigation of programming with numeric variables, which are easier to understand than non-numeric ones. To use variables, we need to write a C++ program, which consists primarily of a list of operations to be performed by the computer, along with directions that influence how these operations are to be translated into machine instructions.

That led us into a discussion of why and how our C++ program is translated into machine instructions by a compiler. We examined an example program that contained simple source code statements, including some that define variables and others that use those variables along with constants to calculate results. We covered the symbols that are used to represent the operations of addition, subtraction, multiplication, division, and assignment, which are +, -, *, /, and = respectively. While the first four of these operators should be familiar to you, the last one is a programming notion rather than a mathematical one. This may be confusing because the operation of assignment is expressed by the = sign, but is not the same as mathematical equality. For example, the statement x = 3; does not mean "x is equal to 3", but rather "set the variable x to the value 3". After this discussion of the structure of statements in C++, we started an exploration of how the CPU actually stores and manipulates data in memory. The topics covered in this section included the order in which multibyte data items are stored in memory and the use of general registers to manipulate data efficiently.

Then we spent some time pretending to be a compiler, to see how a simple C++ program looks from that point of view, in order to improve our understanding of what the compiler does with our programs. This exercise involved keeping track of the addresses of variables and instructions and watching the effect of the instructions on the general registers and memory locations. During this exploration of the machine, we got acquainted with the machine language representation of instructions, which is the actual form that our executable programs take in memory. After a thorough examination of what the compiler does with our simplified example of source code at compile time, we followed what would happen to the registers and memory locations at run time (that is, if the sample code were actually executed).

Then we began to look at two data types that can hold nonnumeric data, namely the char and the string. The char corresponds to 1 byte of storage, and therefore can hold one character of data. Examples of appropriate values for a char variable include letters (a-z, A-Z), digits (0-9), and special characters (e.g., , . ! @ # $ %). A char can also represent a number of other "nonprintable" characters such as the "space", which causes the output position on the screen to move to the next character. Actually, a char can also be used as a "really short" numeric variable, but that's mostly a holdover from the days when memory was a lot more expensive, and every byte counted.

One char doesn't hold very much information by itself, so we often want to deal with groups of them as a single unit; an example would be a person's name. This is the province of the string variable type: variables of this type can handle an indefinitely long group of chars.

At the beginning of our sample program for strings and chars, we encountered a new construct, the #include statement. This tells the compiler where to find instructions on how to handle data types such as strings, about which it doesn't have any built-in knowledge. Then we came across the line int main(), which indicates where we want to start executing our program. A C++ program always starts execution at the place indicated by such a line. We also investigated the meaning of int, which must always be the return type of main. This return type tells the compiler what sort of data this program returns to the operating system when it finishes executing; the return value can be used to determine what action a batch file should take next.

As we continued looking at the sample program for strings and chars, we saw how to assign literal values to both of these types, and noted that two different types of quotes are used to mark off the literal values. The single quote (') is used in pairs to surround a literal char value consisting of exactly one char, such as 'a'; and the double quote (") is used in pairs to surround a literal string value of the C string literal type, such as "This is a test".43 We also investigated the reason for these two different types of literal values, which involves the notion of a null byte (a byte with the value 0); this null byte is used to mark the end of a C string literal in memory.

This led us to the discussion of the ASCII code, which is used to represent characters by binary values. We also looked at the fact that the same bytes can represent either a numeric value or a C string literal, depending on how we use those bytes in our program. That's why it's so important to tell the compiler which of these possibilities we have in mind when we write our programs. The way in which the compiler regulates our access to variables by their type is called the type system; C++ uses static type checking, in which types are determined at compile time rather than being deferred to run time (dynamic type checking). This is one of the reasons that C++ programs can be made more robust than programs written in languages that use dynamic type checking.

After a short discussion of some of the special characters that have a predefined meaning to the compiler, we took an initial glance at the mechanisms that allow us to get information into and out of the computer, known as I/O. We looked at the << function, which provides display on the screen when coupled with the built-in destination called cout. Immediately afterwards, we encountered the corresponding input function >> and its partner cin, which team up to give us input from the keyboard.

Next, we went over some program organization concepts including the if statement, which allows a program to choose between two alternatives; the while statement, which causes another statement to be executed while some condition is true; and the block, which allows several statements to be grouped together into one logical statement. Blocks are commonly used to enable several statements to be controlled by an if or while statement.

At last we were ready to write a simple program that does something resembling useful work, and we did just that. The starting point for this program, as with all programs, was to define exactly what the program should do; in this case, the task was to keep track of the weight of the heaviest pumpkin at a county fair. The next step was to define a solution to this problem in precise terms. Next, we broke the solution down into steps small enough to be translated directly into C++. Of course, the next step after that was to do that translation. Finally, we went over the C++ code, line by line, to see what each line of the program did.

3.19. Conclusion

We've come a long way from the beginning of this chapter. Starting from basic information on how the hardware works, we've made it through our first actual, runnable program. By now, you should have a much better idea of whether you're going to enjoy programming (and this book). Assuming you aren't discouraged on either of these points, let's proceed to gather some more tools so we can undertake a bigger project.

3.20. Answers to Exercises

1. 3c43. In case you got a different result, here's a little help:
a. If you got the result 433a, you started at the wrong address.
b. If you got the result 433c, you had the bytes reversed.
c. Finally, if you got 3a43, you made both of these mistakes.
If you made one or more of these mistakes, don't feel too bad; even experienced programmers have trouble with hexadecimal values once in awhile. That's one reason we use compilers and assemblers rather than writing everything in hex!
2. "HELLO". If you couldn't figure out what the "D" at the beginning was for, you started at the wrong place.
3. Figure 3.25 is Susan's answer to this problem.
FIGURE 3.25. First dinner party program (code\basic05.cpp)
#include <iostream>
using namespace std;

int main()
{
short n;

cout << "Please type in the number of guests ";
cout << "of your dinner party. ";
cin >> n;

cout << "A table for " << n+1 << "is ready. ";

return 0;
}

By the way, the reason that this program uses two lines to produce the sentence "Please type in the number of guests of your dinner party." is so that the program listing will fit on the page properly. If you prefer, you can combine those into one line that says:
cout << "Please type in the number of guests of your dinner party. ";.
Of course, this also applies to the next exercise. Here's the discussion that Susan and I had about this exercise:
Susan: I would have sent it sooner had I not had the last cout arrows going like this >> (details).<G> Also, it just didn't like the use of endl; at the end of the last cout statement. It just kept saying "parse error".
Steve: If you wrote something like
cout << "A table for " << n+1 << "is ready. " << "endl;"
then it wouldn't work for two reasons. First, "endl;" is just a character string, not anything recognized by <<. Second, you're missing a closing ;, because characters inside quotes are treated as just plain characters by the compiler, not as having any effect on program structure.
The correct way to use endl in your second output statement is as follows:
cout << "A table for " << n+1 << "is ready. " << endl;
By the way, you might want to add a " " in front of the is in is ready, so that the number doesn't run up against the is. That would make the line look like this:
cout << "A table for " << n+1 << " is ready. " << endl;
Susan: Okay.
4. Figure 3.26 is Susan's answer to this problem, followed by our discussion.
FIGURE 3.26. Second dinner party program (code\basic06.cpp)
#include <iostream>
using namespace std;

int main()
{
short n;

cout << "Excluding yourself, please type the ";
cout << "number of guests in your dinner party.\n";

cin >> n;

if (n>20)
cout << "Sorry, your party is too large. ";
else
cout << "A table for " << n+1 << " is ready. ";

return 0;
}
Steve: Congratulations on getting your program to work!
Susan: Now, let me ask you this: can you ever modify else? That is, could I have written else (n>20)?
Steve: You can say something like what is shown in Figure 3.27.
FIGURE 3.27. else if example
if (x < y)
{
cout << "x is less than y" << endl;
}
else
{
if (x > y)
cout << "x is greater than y" << endl;
else
cout << "x must be equal to y!" << endl;
}
In other words, the controlled block of an if statement, or an else statement, can have another if or else inside it. In fact, you can have as many "nested" if or else statements as you wish; however, it's best to avoid very deep nesting because it tends to confuse the next programmer who has to read the program.
5. The answer to this problem should look like Figure 3.28.
FIGURE 3.28. Name and age program (code\basic07.cpp)
#include <iostream>
#include <string>
using namespace std;

int main()
{
string name;
short age;

cout << "What is your first name? ";
cin >> name;

cout << "Thank you, " << name << endl;

cout << "What is your age? ";
cin >> age;

if (age < 53)
cout << "My, what a youngster!" << endl;
else
cout << "That is very old, " << name << ". " << endl;

return 0;
}
One point that might be a bit puzzling in this program is why it's not necessary to add an << endl to the end of the lines that send data to cout before we ask the user for input. For example, in the sequence:

cout << "What is your first name? ";
cin >> name;
how do we know that the C string literal "What is your first name? " has been displayed on the terminal before the user has to type in the answer? Obviously, it would be hard for the user to answer our request for information without a clue as to what we're asking for.
As it happens, this is a common enough situation that the designers of the iostream library have anticipated it and solved it for us. When we use that library to do output to the screen and then request input from the keyboard, we can be sure that any screen output we have already requested will be displayed before any input is requested from the user via the keyboard.
That wasn't the only subtle point that this problem raised. You'll be happy (or at least unsurprised) to hear that Susan and I had quite a discussion about this problem and its solution:
Susan: When I was trying to put that period in the answer, I finally got it to work with double quotes. But then I thought that maybe it should have been surrounded by single quotes ' instead of double quotes. It worked with a double quote but since it was only one character it should have been a single quote, so I went back and changed it to a single quote and the compiler didn't like that at all. So I put it back to the double. So what is the deal?
Steve: You should be able to use 'x' or "x" more or less interchangeably with <<, because it can handle both of those data types (char and C string literal, respectively). However, they are indeed different types. The first one specifies a literal char value, whereas the second specifies a C string literal value. A char value can only contain one character, but a C string literal can be as long as you want, from none to hundreds or thousands of characters.
Susan: Here's the line that gave me the trouble:

cout << "That is very old, " << name << ". " << endl;

Remember I wanted to put that period in at the end in that last line? It runs like this but not with the single quotes around it. That I don't understand. This should have been an error. But I did something right by mistake <G>. Anyway, is there something special about the way a period is handled?
Steve: I understand your problem now. No, it's not the period; it's the space after the period. Here are four possible versions of that line:

1. cout << "That is very old, " << name << ". " << endl;

2. cout << "That is very old, " << name << '. ' << endl;

3. cout << "That is very old, " << name << "." << endl;

4. cout << "That is very old, " << name << '.' << endl;

None of these is exactly the same as any of the others. However, 1, 3, and 4 will do what you expect, whereas 2 will produce weird looking output, with some bizarre number where the "." should be. Why is this? It's not because "." is handled specially, but because the space (" "), when inside quotes, either single or double, is a character like any other character. Thus, the expression '. ' in line 2 is a "multicharacter constant", which has a value dependent on the compiler; with the compiler on the CD, you'll get a short value equal to (256 * the ASCII value of the period) + the ASCII value of the space. This comes out to 11808, as I calculate it. So the line you see on the screen may look like this:
That is very old, Joe11808
Now why do all of the other lines work? Well, 1 works because a C string literal can have any number of characters and be sent to cout correctly; 3 works for the same reason; and 4 works because '.' is a valid one-character constant, which is another type that << can handle.
I realize it's hard to think of the space as a character when it doesn't look like anything; in addition, you can add spaces freely between variables, expressions, and so forth, in the program text. However, once you're dealing with C string literals and literal character values, the space is just like any other character.
Susan: So it is okay to use single characters in double quotes? If so, why bother with single quotes?
Steve: Single quotes surround a literal of type char. This is a 1byte value that can be thought of (and even used) as a very short number. Double quotes surround a literal value of type "C string literal". This is a multibyte value terminated by a 0 byte, which cannot be used or treated as a number.
Susan: I am not too clear on what exactly the difference is between the char and "C string literal". I thought a char was like an alpha letter, and a string was just a bunch of letters.
Steve: Right. The difference is that a C string literal is variable length, and a char isn't; this makes a lot of difference in how they can be manipulated.
Susan: Am I right in thinking that a char could also be a small number that is not being used for calculations?
Steve: Or that is used for (very small) calculations; for instance, if you add 1 to the value 'A', you get the value for 'B'. At least that's logical.
Susan: What do you mean by "terminated by a 0 byte"? That sounds familiar; was that something from an earlier chapter which is now ancient history?
Steve: Yes, we covered that some time ago. The way the program can tell that it's at the end of a C string literal (which is of variable length, remember) is that it gets to a byte with the value 0. This wouldn't be my preferred way to specify the size of a variable-length string, but it's too late to do anything about it; it's built into the compiler.
Susan: When you say a C string literal, do you mean the C programming language in contrast to other languages?
Steve: Yes.
Susan: All right, then the 0 byte used to terminate a C string literal is the same thing as a null byte?
Steve: Yes.
Susan: Then you mean that each C string literal must end in a 0 so that the compiler will know when to stop processing the data for the string?
Steve: Yes.
Susan: Could you also just put 0? Hey, it doesn't hurt to ask. I don't see the problem with the word hello; it ends with an o and not a 0. But what if you do need to end the sentence with a 0?
Steve: It's not the digit '0', which has the ASCII code 30h, but a byte with a 0 value. You can't type in a null byte directly, although you can create one with a special character sequence if you want to. However, there's no point in doing that usually, because all C string literals such as "hello" always have an invisible 0 byte added automatically by the compiler. If for some reason you need to explicitly create a null byte, you can write it as '\0', as in
char x = '\0';
which emphasizes that you really mean a null byte and not just a plain old 0 like this:
char x = 0;
The difference between these two is solely for the benefit of the next programmer who looks at your code; they're exactly the same to the compiler.
6. Figure 3.29 shows Susan's program, which is followed by our discussion.
FIGURE 3.29. Novice program (code\basic08.cpp)
#include <iostream>
#include <string>
using namespace std;

int main()
{
string answer;

cout << "Please respond to the following statement ";
cout << "with either true or false\n";

cout << "Susan is the world's most tenacious novice.\n";
cin >> answer;

if (answer != "true")
if (answer != "false")
cout << "Please answer with either true or false.";

if (answer == "true")
cout << "Your answer is correct\n";

if (answer == "false")
cout << "Your answer is erroneous\n";

return 0;
}
Susan: Steve, look at this. It even runs!
Also, I wanted to ask you one more question about this program. I wanted to put double quotes around the words true and false in the 3rd output statement because I wanted to emphasize those words, but I didn't know if the compiler could deal with that so I left it out. Would that have worked if I had?
Steve: Not if you just added quotes, because " is a special character that means "beginning or end of C string literal". Here's what you would have to do to make it work:
cout << "Please answer with either \"true\" or \"false\".";
The \ is a way of telling the compiler to treat the next character differently from its normal usage. In this case, we are telling the compiler to treat the special character " as "not special"; that is, \" means "just the character double quote, please, and no nonsense". This is called an escape sequence, because it allows you to get out of the trap of having a " mean something special. We also use the \ to tell the compiler to treat a "nonspecial" character as "special"; for example, we use it to make up special characters that don't have any visual representation. You've already seen '\n', the "newline" character, which means "start a new line on the screen".
Susan: So if we want to write some character that means something "special", then we have to use a \ in front of it to tell the compiler to treat it like a "regular" character?
Steve: Right.
Susan: And if we want to write some character that is "regular" and make it do something "special", then we have to use a \ in front of it to tell the compiler that it means something "special"?
Steve: Yes, that's the way it works.
Susan: I now just got it. I was going to say, why would you put the first quotation mark before the slash in `\n', but now I see. Since you are doing an endline character, you have to have quotes on both sides to surround it which you don't usually have to do because the first quotes are usually started at the beginning of the sentence, and in this case the quote was already ended.
Steve: You've got it.
Susan: Another thing I forgot is how you refer to the code in () next to the "if" keywords; what do you call that?
Steve: The condition.
7. Figure 3.30 is Susan's version of this program. Actually, it was her idea in the first place.
FIGURE 3.30. Allowance program (code\basic09.cpp)
#include <iostream>
using namespace std;

int main()
{
short x;

cout << "Elena can increase her $10 allowance each week ";
cout << "by adding new chores." << endl;

cout << "For every extra chore Elena does, she gets ";
cout << "another dollar." << endl;

cout << "How many extra chores were done? " << endl;
cin >> x;

if (x==0)
{
cout << "There is no extra allowance for Elena ";
cout << "this week. " << endl;
}
else
{
cout << "Elena will now earn " << 10 + x;
cout << " dollars this week." << endl;
}

return 0;
}

8. You'll be happy (or at least unsurprised) to hear that Susan and I had quite a discussion about this problem.
Susan: Remember on my "test" program how I finally got that period in there? Then I got to thinking that maybe it should have been surrounded by single quotes ' instead of double quotes. It worked with a double quote but since it was only one character it should have been a single quote, so I went back and changed it to a single quote and the compiler didn't like that at all. So I put it back to the double. So what is the deal?
Steve: You should be able to use 'x' or "x" more or less interchangeably with <<, because it can handle both of those data types (char and C string, respectively). However, they are indeed different types. The first one specifies a literal char value, whereas the second specifies a literal C string value. A char value can only contain one character, but a C string can be as long as you want, from none to hundreds or thousands of characters.
Susan: Here's the line that gave me the trouble:

cout << "That is very old, " << name << ". " << endl;

Remember I wanted to put that period in at the end in that last line? It runs like this but not with the single quotes around it. That I don't understand. This should have been an error. But I did something right by mistake <G>. Anyway, is there something special about the way a period is handled?
Steve: I understand your problem now. No, it's not the period; it's the space after the period. Here are four possible versions of that line:

1. cout << "That is very old, " << name << ". " << endl;

2. cout << "That is very old, " << name << '. ' << endl;

3. cout << "That is very old, " << name << "." << endl;

4. cout << "That is very old, " << name << '.' << endl;

None of these is exactly the same as any of the others. However, 1, 3, and 4 will do what you expect, whereas 2 will produce weird looking output, with some bizarre number where the "." should be. Why is this? It's not because "." is handled specially, but because the space (" "), when inside quotes, either single or double, is a character like any other character. Thus, the expression '. ' in line 2 is a "multicharacter constant", which has a value dependent on the compiler; in the case of the compiler on the CD in the back of the book, you'll get a short value equal to (256 * the ASCII value of the space) + the ASCII value of the period. This comes out to 8238, as I calculate it. So the line you see on the screen may look like this:
That is very old, Joe Smith8238
Now why do all of the other lines work? Well, 1 works because a C string can have any number of characters and be sent to cout correctly; 3 works for the same reason; and 4 works because '.' is a valid one-character constant, which is another type that << can handle.
I realize it's hard to think of the space as a character, when it doesn't look like anything; in addition, you can add spaces freely between variables, expressions, and so forth, in the program text. However, once you're dealing with C strings and literal character values, the space is just like any other character.
Susan: So it is okay to use single characters in double quotes? If so, why bother with single quotes?
Steve: Single quotes surround a literal of type char. This is a 1byte value that can be thought of (and even used) as a very short number. Double quotes surround a literal of type "C string". This is a multibyte value terminated by a 0 byte, which cannot be used or treated as a number.
Susan: I am not too clear on what exactly the difference is between the char and "C string". I thought a char was like a alpha letter, and a string was just a bunch of letters.
Steve: Right. The difference is that a C string is variable length, and a char isn't; this makes a lot of difference in how they can be manipulated.
Susan: Am I right in thinking that a char could also be a small number that is not being used for calculations?
Steve: Or that is used for (very small) calculations; for instance, if you add 1 to the value 'A', you get the value for 'B'. At least that's logical.
Susan: What do you mean by "terminated by a 0 byte"? That sounds familiar; was that something from an earlier chapter which is now ancient history?
Steve: Yes, we covered that some time ago. The way the program can tell that it's at the end of a C string (which is of variable length, remember) is that it gets to a byte with the value 0. This wouldn't be my preferred way to specify the size of a variable-length string, in my opinion, but it's too late to do anything about it; it's built into the compiler.
Susan: When you say a C string, do you mean the C programming language in contrast to other languages?
Steve: Yes.
Susan: All right, then the 0 byte used to terminate a C string is the same thing as a null byte?
Steve: Yes.
Susan: Then you mean that each C string must end in a 0 so that the compiler will know when to stop processing the data for the string?
Steve: Yes.
Susan: Could you also just put 0? Hey, it doesn't hurt to ask. I don't see the problem with the word hello; it ends with an o and not a 0. But what if you do need to end the sentence with a 0?
Steve: It's not the digit '0', which has the ASCII code 30h, but a byte with a 0 value. You can't type in a null byte directly, although you can create one with a special character sequence if you want to. However, there's no point in doing that usually, because all literal C strings such as "hello" always have an invisible 0 byte added automatically by the compiler. If for some reason you need to explicitly create a null byte, you can write it as '\0', as in
char x = '\0';
which emphasizes that you really mean a null byte and not just a plain old 0 like this:
char x = 0;
The difference between these two is solely for the benefit of the next programmer to look at your code; they're exactly the same to the compiler.

1 Please note that C++ is case sensitive, so IF and WHILE are not the same as if and while. You have to use the latter versions when you are referring to the keywords with those names. Although it is possible to define your own variables called IF and WHILE, I don't recommend this, as it will tend to confuse other programmers.

2 However, we haven't yet completely eliminated the possibility of hardware errors, as the floating-point flaw in early versions of the Pentium processor illustrates. In rare cases, the result of the divide instruction in those processors was accurate to only about 5 decimal places rather than the normal 16 to 17 decimal places.

3 This was apparently against the plan administrator's principles.

4 How is the compiler itself translated into machine language so it can be executed? The most common method is to write the compiler in the same language it compiles and use the previous version of the compiler to compile the newest version! Of course, this looks like an infinite regress; how did the first compiler get compiled? By manual translation into assembly language, which was then translated by an assembler into machine language. To answer the obvious question, at some point an assembler was coded directly in machine language.

5 The compiler also does a lot of other work for us, which we'll get into later.

6 By the way, blank lines are ignored by the compiler; in fact, because of the trailing semicolon on each statement, you can even run all the statements together on one line if you want to, without confusing the compiler. However, that will make it much harder for someone reading your code later to understand what you're trying to do. Programs aren't written just for the compiler's benefit but to be read by other people; therefore, it is important to write them so that they can be understood by those other people. One very good reason for this is that more often than you might think, those "other people" turn out to be you, six months later.

7 The // indicates the beginning of a comment, which is a note to you or another programmer. Everything on a line after // is ignored by the compiler.

8 Except that the C++ standard library header files supplied with the compiler, such as string, often have no extension at all. Also, other compilers sometimes use other extensions for implementation files, such as .cc, and for header files, such as .hpp.

9 Other kinds of variables can hold larger (and smaller) values; we'll go over them in some detail in future chapters.

10 At the risk of boring experienced C programmers, let me reiterate 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 =. In fact, there is no equivalent in C++ to the mathematical notion of equality. We have only the assignment operator = and the comparison operator ==, which we will encounter in the next chapter. The latter is used in if statements to determine whether two expressions have the same value. All of the valid comparison operators are listed in Figure 4.5.

11 If you have any programming experience whatever, you may think that I'm spending too much effort on this very simple point. But I can report from personal experience that it's not necessarily easy for a complete novice to grasp. Furthermore, without a solid understanding of the difference between an algebraic equality and an assignment statement, that novice will be unable to understand how to write a program.

12 Actually, the C++ language does not require that a short variable contain exactly two bytes. However, it does on current Intel CPUs and other current CPUs of which I am aware.

13 Besides these general registers, a dedicated register called esp plays an important role in the execution of real programs. We'll see how it does this in Chapter 5.

14 This is not the only possible solution to this problem, nor necessarily the best one. For example, in many Motorola CPUs, you specify the length of the variable directly in the instruction, so loading a word (i.e., 2-byte) variable might be specified by the instruction move.w, where the .w means "word". Similarly, a longword (i.e., 4-byte) load might be specified as move.l, where the .l means "long word".

15 It's also possible to load a 2-byte value into a 32-bit (i.e., 4-byte) register such as eax and have the high part of that register set to 0 in one instruction, by using an instruction designed specifically for that purpose. This approach has the advantage that further processing can be done with the 32-bit registers.

16 The number inside the brackets [ ] represents a memory address.

17 Luckily, we won't run into this problem in this book. However, it is very common in dealing with networks of computers, and there are industry standards set up to allow diverse types of computers to coexist in a network.

18 As I've mentioned previously, blank lines are ignored by the compiler; you can put them in freely to improve readability.

19 However, I've cheated here by using small enough numbers in the C++ program that they are the same in hex as in decimal.

20 The real compiler on the CD actually uses 4-byte addresses, but this doesn't change any of the concepts involved.

21 These addresses are arbitrary; a real compiler will assign addresses to variables and machine instructions by its own rules.

22 In case you were wondering, the most common pronunciation of char has an a like the a in "married", while the ch sounds like "k".

23 Again, the C++ language does not require that a byte have exactly eight bits, just that it has at least eight bits. On the other hand, by definition a char variable occupies exactly one byte of storage, however big a byte may be.

24 As we will see shortly, not all characters have visible representations; some of these "nonprintable" characters are useful in controlling how our printed or displayed information looks.

25 An integral type is a type of data that can hold an integer. This includes short, int, and char, the last of these mostly for historical reasons.

26 Unfortunately, there is no guarantee that shorts will still be 16 bits on a 64-bit compiler, but there isn't much I can do about that.

27 Actually, this is an oversimplification. Some code that we write may be executed before the beginning of main, but only under unusual circumstances that we will not encounter in this book. If you're burning with curiosity as to how this can be done (and why), there's an explanation in the section entitled "Executing Code before the Beginning of main" on page 744.

28 If you look at someone else's C++ program, you're likely to see a different style for lining up the {} to indicate where a section of code begins and ends. As you'll notice, my style puts the { and } on separate lines rather than running them together with the code they enclose, to make them stand out, and indents them further than the conditional statement that controls the section of code. I find this the clearest, but this is a matter where there is no consensus. The compiler doesn't care how you indent your code or whether you do so at all; it's a stylistic issue.

29 Please note that there is a space (blank) character at the end of that C string literal, after the word "test". That space is part of the literal value.

30 Warning: Every character inside the quotes has an effect on the value of the literal, whether the quotes are single or double; even "invisible" characters such as the space (` ') will change the literal's value. In other words, the line c1 = 'A'; is not the same as the line c1 = 'A ';. The latter statement may or may not be legal, depending on the compiler you're using, but it is virtually certain not to give you what you want, which is to set the variable c1 to the value equivalent to the character 'A'. Instead, c1 will have some weird value resulting from combining the 'A' and the space character. In the case of a string value contained in double quotes, multiple characters are allowed, so "A B" and "AB" both make sense, but the space still makes a difference; namely, it keeps the 'A' and 'B' from being next to one another.

31 I don't want to mislead you about this notion of a byte having the value 0; it is not the same as the representation of the decimal digit "0". As we'll see, each displayable character (and a number of invisible ones) is assigned a value to represent it when it's part of a string or literal value (i.e., a C string literal or char literal). The 0 byte I'm referring to is a byte with the binary value 0.

32 Happily, we can improve on it in most other circumstances, as you'll see later.

33 You may wonder why I have to specify that the codes for each case of letters run consecutively. Believe it or not, there are a number of slightly differing codes collectively called EBCDIC (Extended Binary Coded Decimal Interchange Code), in which this is not true! Eric Raymond's amusing and interesting book, The New Hacker's Dictionary, has details on this and many other historical facts.

34 The line #include <iostream> is necessary here to tell the compiler about cout and how it works. We'll get into this in a bit more detail shortly.

35 In case you were wondering, cout is pronounced "see out", while cin is pronounced "see in".

36 The reason a space ends a string is that the designers of the C++ standard library thought that would be more convenient than having everything up to the end of a line read into one string. I don't agree with this, but the advantages of using the standard library generally outweigh its disadvantages, so we just have to put up with any inconveniences that it causes.

37 If you think the name of that bank is funny, you should get a copy of The Most of S. J. Perelman (ISBN 0-671-41871-8). Unfortunately, it's out of print, but you might be able to find a used one at Amazon.com or another bookseller.

38 This explanation assumes that the "10000" is the balance in dollars. Of course, this doesn't account for the possibility of balances that aren't a whole number of dollars, and there's also the problem of balances greater than $32767, which wouldn't fit into a short. As we'll see in Chapter 9, both of these problems can be solved by using a different data type called double.

39 Why do we need parentheses around the expression Guess != Secret? The conditional expression has to be in parentheses so that the compiler can tell where it ends, and the statement to be controlled by the while begins.

40 Not until "Definitions" on page 856 in Chapter 12, to be exact.

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.

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.

43 The C string literal type is called that because it is inherited from C, which did not have a real string type such as the C++ string. These two types are quite different, although related in a way that we will see in a later chapter.


TOC PREV NEXT INDEX