Day 2
Week1
40 Day 2
If…
There are some aspects of programming that are common to all programming languages.
One such item that C++ has in common with other programming languages is the if
statement. The if statement is used to test for a condition and then execute sections of code
based on whether that condition is true or false. Here’s an example:
int x;
cout << “Enter a number: “;
cin >> x;
if (x > 10)
cout << “You entered a number greater than 10.” <<>
This code asks for input from the user. If the user enters a number greater than 10, the
expression x > 10 evaluates to true and the message is displayed; otherwise nothing is
displayed. Note that if the conditional expression evaluates to true, the statement immediately
following the if expression is executed.
The if statement is used to test for a condition and then execute sections of code
based on whether that condition is true or false.
Be sure not to follow the if expression with a semicolon. A semicolon
by itself represents a blank statement in code. If you accidentally follow
your if expression with a semicolon, the compiler will interpret the
blank statement as the statement to execute if the expression evaluates
to true. Here’s an example:
if (x == 10); // Warning! Extra semi-colon!
DoSomething(x);
In this case, the DoSomething() function will always be executed because
the compiler does not see it as being the first statement following the if
expression. Because this code is perfectly legal (albeit useless), the
compiler will not warn you that anything is amiss.
If you have multiple lines of code that should be executed if the conditional expression is true,
you would need braces to block those lines:
if (x > 10) {
cout << “The number is greater than 10” <<>
DoSomethingWithNumber(x);
}
NEW TERM
NOTE
Wading In Deeper 41
2
If the conditional expression evaluates to false, the code block associated with the if
expression is ignored, and program execution continues with the first statement following the
code block.
C++ contains a lot of shortcuts. One of those shortcuts involves using
just the variable name to test for true. Look at this code:
if (fileGood) ReadData();
This method is a shortcut for the longer form, which is illustrated with
this line:
if (fileGood == true) ReadData();
This example uses a bool variable, but any data type will do. The
expression evaluates to true as long as the variable contains any nonzero
value. You can test for false by applying the logical NOT (!)
operator to a variable name:
bool fileGood = OpenSomeFile();
if (!fileGood) ReportError();
Learning the C++ shortcuts will help you write code that contains a
degree of elegance. Knowing the shortcuts also helps you understand
C++ code that you read in examples and sample listings.
In some cases you want to perform an action if the conditional expression evaluates to true
and perform some other action if the conditional expression evaluates to false. In this case
you can implement the else statement:
if (x == 20) {
DoSomething(x);
}
else {
DoADifferentThing(x);
}
The else statement is used in conjunction with the if statement and identifies
sections of code that are executed when the if statement fails (that is, evaluates to
false).
In this example one of the two functions will be called, but not both.
NOTE
NEW TERM
42 Day 2
Note that the equality operator is the double equal sign (==) and that
the assignment operator is the single equal sign (=). A common coding
mistake is to use the assignment operator where you meant to use the
equality operator. For instance, if the previous example were inadvertently
written like this:
if (x = 20) {
DoSomething(x);
}
x would be assigned the value of 20. Because this operation would be
successful, the expression would evaluate to true. A bug like this,
although seemingly obvious, can be hard to spot, so take care when
testing for equality.
You can nest if statements if needed. Nesting is nothing more than following an if statement
with one or more additional if statements. Here’s an example:
if (x > 10)
if (x <>
cout << “X is between 10 and 20” <<>
Keep in mind that these are simplified examples. In the real world you can get lost in the maze
of braces that separate one function block from the next. Take a look at this code snippet,
for instance:
if (x > 100) {
y = 20;
if (x > 200) {
y = 40;
if (x > 400) {
y = 60;
DoSomething(y);
}
}
}
else if (x < -100) {
y = -20;
if (x < -200) {
y = -40;
if (x < -400) {
y = -60;
DoSomething(y);
}
}
}
Even this is a fairly simple example, but you get the idea.
WARNING
Wading In Deeper 43
2
The C++Builder Code Editor has a handy function to help you find
matching braces. Position the cursor on the brace for which you want
to find the corresponding brace. Press either the Alt+[ or the Alt+] key
combination, and the cursor will be positioned at the brace you are
looking for. It doesn’t matter whether you start on the opening brace or
the closing brace. In either case, the matching brace will be located.
If a section of code contains more than two or three consecutive if
statements testing for different values of the same variable, it might be a
candidate for a switch statement. The switch statement is discussed
later in this chapter in the section “The switch Statement.”
Earlier I mentioned C++ shortcuts. There is a shortcut for the if-else combination. Look
at the following code:
if (direction == EAST) lost = true;
else (lost = false);
These two lines can be condensed into a single line:
direction == EAST ? lost = true : lost = false;
Although this shortcut notation might look a little odd at first, you will quickly learn to
recognize it when you see it. The if statement is heavily used in C++. It’s pretty straightforward,
so you won’t have any trouble with it. The main thing is keeping all of the braces
straight.
The if statement, Form 1:
if (cond_expr) {
true_statements;
}
else {
false_statements;
}
If the conditional expression, cond_expr, is true (nonzero), the block of code represented by
true_statements is executed. If the optional else clause is specified, the block of code
represented by false_statements is executed when the conditional expression, cond_expr, is
false.
TIP
TIP
SYNTAX
t
t
44 Day 2
The if statement, Form 2:
if (cond_expr_1) {
true_statements_1;
}
else if (cond_expr_2) {
true_statements_2;
}
else {
false_statements;
}
If the conditional expression cond_expr_1 is true (nonzero), the block of code represented
by true_statements_1 is executed. If it is false and the conditional expression cond_expr_2
is true, the block of code represented by true_statements_2 is executed. If both cond_expr_1
and cond_expr_2 are false, the block of code represented by false_statements is executed.
Thrown for a
The loop is a common element in all programming languages. A loop can be used to iterate
through an array, to perform an action a specific number of times, to read a file from
disk…the possibilities are endless. I will examine several types of loops here, and for the most
part they work in very similar ways. All loops have these common elements:
n A starting point
n A body, usually enclosed in braces, that contains the statements to execute on each
pass
n An ending point
n A test for a condition that determines when the loop should end
n Optional use of the break and continue statements
A loop is an element in a programming language that is used to perform an action
a specific number of times.
The starting point for the loop is one of the C++ loop statements (for, while, or do) followed
by an opening brace. The body contains the statements that will execute each time through
the loop. The body can contain any valid C++ code. The ending point for the loop is the
closing brace.
Most loops work something like this: The loop is entered and the test condition is evaluated.
If the test condition is not met, the body of the loop is executed. When program execution
reaches the bottom of the loop (usually the closing brace), it jumps back to the top of the loop,
where the test condition is again evaluated. If the test condition is not met, the whole process
is repeated. If the test condition is met, program execution jumps to the line of code
t
s
NEW TERM
Wading In Deeper 45
2
immediately following the loop code block. The exception to this description is the do-while
loop, which tests for the condition at the bottom of the loop rather than at the top.
The test condition tells the loop when to stop executing. In effect the test condition says, for
example, “Keep doing this until x is equal to 10,” or, “Keep reading the file until the end-offile
is reached.” Once the loop starts it continues to execute the body of the loop until the test
condition is met.
It’s easy to accidentally write a loop so that the test condition is never
met. This will result in a program that is locked up or hung. Your only
recourse at that point is to press Ctrl+Alt+
Windows Close Program box will come up and will display the name
of your program with (Not Responding) next to it. You’ll have to select
your program from the list and click End Task to terminate the
runaway program.
In C++Builder you typically run a program using the Run button on
the Speed Bar or by pressing F9. If you need to kill a runaway program
that was run from the IDE, you can choose Run | Reset Process from
the main menu or press Ctrl+F2 on the keyboard.
Given that general overview, let’s take a look at each type of loop individually.
The for
The for loop is probably the most commonly used type of loop. It takes three parameters:
the starting number, the test condition that determines when the loop stops, and the
increment expression.
The for loop statement:
for (initial; cond_expr; adjust) {
statements;
}
The for loop repeatedly executes the block of code indicated by statements as long as the
conditional expression, cond_expr, is true (nonzero). The state of the loop is initialized by
the statement initial. After the execution of statements, the state is modified using the
statement indicated by adjust.
WARNING
TIP
SYNTAX
t
s
46 Day 2
That won’t make much sense until you see some examples. First take a look at a typical for
loop:
for (int i=0;i<10;i++)>
cout << “This is iteration “ <<>
}
This code will result in the statement inside the braces being executed 10 times. The first
parameter, int i=0, tells the for loop that it is starting with an initial value of 0. (In this case
I am declaring and assigning a variable inside the for statement. This is perfectly legal and
is common in for loops.) The second parameter, i<10, tells the loop to keep running as long
as the variable i is less than 10. Because I’m starting with 0, I need to stop before i is equal
to 10. The last parameter, i++, increments the variable i by one each time through the loop.
The use of the variable name i (presumably for iterator) is traditional in
for loops. Naturally, any variable name can be used, but you will often
see i used in for loops.
Let’s look at a variation of this code. The following code snippet will achieve exactly the
opposite effect as the first example:
for (int i=10;i>0;i--) {
cout << “This is iteration “ <<>
}
This time I’m starting with 10, stopping when i is equal to 0, and decrementing i by one on
each pass. This is an example of a loop that counts backward.
In the previous examples, the opening and closing braces are not strictly
required. If no opening and closing braces are supplied, the statement
immediately following the for statement is considered the body of the
loop. It’s not a bad idea to include the braces for clarity and readability
even when they aren’t strictly required.
Let’s write a little program that illustrates the use of the for loop. You can enter, compile, and
run the program found in Listing 2.1. It’s called FORLOOP.CPP, and you can find it at
http://www.mcp.com/sams/codecenter.html. The output from FORLOOP.CPP is shown in
Figure 2.1.
NOTE
NOTE
Wading In Deeper 47
2
Listing 2.1. FORLOOP.CPP.
1: #include
2: #include
3: #pragma hdrstop
4:
5: int main(int argv, char** argc)
6: {
7: cout <<>
8: int i;
9: for (i=0;i<10;i++)>
10: cout << “Iteration number “ <<>
11: }
12: cout <<>
13: for (i=10;i>0;i--) {
14: cout << “Iteration number “ <<>
15: }
16: getch();
17: return 0;
18: }
Figure 2.1.
The output from
FORLOOP.CPP.
By now you know that the loop starting number can be any value you like (assuming it fits
the range of the data type selected, of course). The test condition can be any C++ expression
that eventually evaluates to true. The test value could be a numeric constant as used in the
examples here, it could be a variable, or it could be the return value of a function call. The
following are examples of valid test conditions:
for (int i=0;i <>
for (int i=1;i == numberOfElements;i++) {...}
for (int i=0;i <= GetNumberOfElements();i+=2) {...}
Take a look at the last example. Notice the last parameter of the for statement. In this case
I am incrementing the counter by 2 each time through the loop. The increment parameter
can increment by any amount you want. For instance, this loop counts by 10s:
for (int i=0;i<100;i+=10)>
48 Day 2
Now that you’ve seen the for loop in action, it won’t be too difficult to apply the same
concepts to the while and do-while loops. Let’s take a look at those now.
The while Loop
The while loop differs from the for loop in that it contains only a test condition that is
checked at the start of each iteration. As long as the test condition is true, the loop keeps
running. Here’s an example:
int x;
while (x <>
x = DoSomeCalculation();
}
In this example I am calling a function that I assume will eventually return a value greater than
1,000. As long as the return value from this function is less than 1,000, the while loop
continues to run. When the variable x contains a value greater than or equal to 1,000, the test
condition yields false, and program execution jumps to the first line following the while
loop’s ending brace. A common implementation of a while loop uses a bool as a test variable.
The state of the test variable can be set somewhere within the body of the loop:
bool done = false;
while (!done) {
// some code here
done = SomeFunctionReturningABool();
// more code
}
At some point it is expected that the variable done will be false and the loop will terminate.
The program in Listing 2.2 illustrates the use of the while loop.
Listing 2.2. WHILETST.CPP.
1: #include
2: #include
3: #pragma hdrstop
4: int main(int argv, char** argc)
5: {
6: cout <<>
7: int i = 6;
8: while (i-- > 0) {
9: cout <<>
10: cout << “ problems to worry about.”;
11: }
12: cout << “\b!\nYipee!”;
13: cout <<>
14: getch();
15: return 0;
16: }
Wading In Deeper 49
2
The while loop statement:
while (cond_expr) {
statements;
}
The while loop repeatedly executes the block of code indicated by statements as long as the
conditional expression, cond_expr, is true (nonzero). The state of the loop must be initialized
prior to the while statement, and modification of the state must be explicit in the block of
code. When the conditional expression, cond_expr, evaluates to false the loop terminates.
The do-while Loop
The do-while loop is nearly identical to the while loop. The distinction between the two is
important, though. As you can see from Listing 2.2, the while loop checks the conditional
expression at the top of the loop. In the case of the do-while loop, the conditional expression
is checked at the bottom of the loop:
bool done = false;
do {
// some code
done = SomeFunctionReturningABool();
// more code
} while (!done)
Whether you use a while or a do-while loop depends on what the loop itself does.
The do-while loop statement:
do {
statements;
} while (cond_expr)
The do loop repeatedly executes the block of code indicated by statements as long as the
conditional expression, cond_expr, is true (nonzero). The state of the loop must be initialized
prior to the do statement, and modification of the state must be explicit in the block of code.
When the conditional expression, cond_expr, evaluates to false, the loop terminates.
goto
I’ll mention goto just so you know it exists. The goto statement allows you to jump program
execution to a label that you have previously declared by using a term followed by a colon.
The following code snippet illustrates this:
bool done = false;
startPoint:
// do some stuff
if (!done) goto(startPoint);
// loop over, moving on...
SYNTAX
t
s
SYNTAX
t
s
50 Day 2
It is not necessary to use braces here because all lines of code between the goto statement and
the label will be executed.
The goto statement is considered bad form in a C++ program. Just
about anything you can accomplish with goto you can accomplish with
a while or do-while loop. Very few self-respecting C++ programmers
have goto in their code. If you are moving to C++ from another
language that uses goto statements, you will find that the basic structure
of C++ makes the goto statement unnecessary.
The goto statement:
goto label
.
.
.
label:
The goto statement unconditionally transfers the program execution sequence to the label
represented by label.
continue and break
Before we leave this discussion of loops, you need to know about two keywords that help
control program execution in a loop. The continue statement is used to force program
execution back to the top of the loop. For example, you might have part of a loop that you
don’t want to execute if a particular test returns true. In that case you would use continue
to jump back to the start of the loop and avoid execution of any code below the continue
statement:
bool done = false;
while (!done) {
// some code
bool error = SomeFunction();
if (error) continue; // jumps to the top of the loop
// other code that will execute only if no error occured
}
The break statement is used to halt execution of a loop prior to the loop’s normal test
condition being met. For example, you might be searching an array of ints for a particular
number. By breaking execution of your search loop when the number is found, you can
obtain the array index where the number is located:
int index = 0;
int searchNumber = 50;
NOTE
SYNTAX
t
s
Wading In Deeper 51
2
for (int i=0;i
if (myArray[i] == searchNumber) {
index = i;
break;
}
if (index)
cout << “Number found at index “ <<>
else
cout << “Number not found in array.” <<>
There are many situations in which the continue and break statements are useful. As with
most of what I’ve been talking about, it will take some experience programming in C++ before
you discover all the possible uses for continue and break.
The switch Statement
The switch statement could be considered a glorified if statement. It allows you to execute
one of several code blocks based on the result of an expression. The expression might be a
variable, the result of a function call, or any valid C++ expression that evaluates to an
expression. Here is an example of a switch statement:
switch(amountOverSpeedLimit) {
case 0 : {
fine = 0;
break;
}
case 10 : {
fine = 20;
break;
}
case 15 : {
fine = 50;
break;
}
case 20 :
case 25 :
case 30 : {
fine = amountOverSpeedLimit * 10;
break;
}
default : {
fine = GoToCourt();
jailTime = GetSentence();
}
}
Several parts make up a switch statement. First, you can see that there is the expression, which
in this example is the variable amountOverSpeedLimit (remember, I warned you about long
variable names!). Next, the case statements test the expression for equality. If
amountOverSpeedLimit equals 0 (case 0 :), the value 0 is assigned to the variable fine. If
52 Day 2
amountOverSpeedLimit is equal to 10, a value of 20 is assigned to fine, and so on. In each of
the first three cases you see a break statement. The break statement is used to jump out of
the switch block—it means that a case matching the expression has been found, and the rest
of the switch statement can be ignored. Finally, you see the default statement. The code
block following the default statement will be executed if no matching cases are found.
Notice that cases 20 and 25 have no statements following them. If the expression
amountOverSpeedLimit evaluates to 20 or 25, those cases fall through and the next code block
encountered will be executed. In this situation, the values 20, 25, or 30 will all result in the
same code being executed.
Don’t forget your break statements! Without break statements the
switch will continue on even after finding a match and may execute
code you didn’t intend to be executed. Sometimes that is how you want
your switch to perform, but most of the time it is not.
Inclusion of the default statement is not mandatory. You could write a switch without a
default statement:
switch (x) {
case 10 : DoSomething(); break;
case 20 : DoAnotherThing(); break;
case 30 : TakeABreak();
}
Note that there is no break statement following the last case statement. Because this is the
last line of the switch, there is no point in including the break statement for this line.
As I said earlier, you might want to use a switch if you find that you have several if statements
back-to-back. The switch is a bit clearer to others reading your program.
The switch statement:
switch (expr) {
case value_1:
statements_1;
break;
case value_2:
statements_2;
break;
.
.
.
case value_n:
statements_n;
break;
WARNING
SYNTAX
t
t
Wading In Deeper 53
2
default:
dflt_statements;
break;
}
The switch statement offers a way to execute different blocks of code depending on various
values of an expression (expr). The block of code represented by statements_1 is executed
when expr is equal to value_1, the block of code represented by statements_2 when expr is
equal to value_2, and so on through the block of code represented by statements_n when
expr is equal to value_n. When expr is not equal to any of value_1 through value_n, the block
of code at dflt_statements is executed. The break statements are optional.
Learning About Scope
The term scope refers to the visibility of variables within different parts of your program. Most
variables have local scope. This means that the variable is visible only within the code block
in which it is declared. Take a look at the program in Listing 2.3.
The term scope refers to the visibility of variables in different parts of your program.
Listing 2.3. SCOPE.CPP.
1: #include
2: #include
3: #pragma hdrstop
4: int x = 20;
5: void CountLoops(int);
6: int main(int, char**)
7: {
8: int x = 40;
9: int i = 0;
10: cout << “In main program x = “ <<>
11: bool done = false;
12: while (!done) {
13: int x;
14: cout <<>
15: cin >> x;
16: if (x != -1) {
17: cout << x =" “">
18: CountLoops(++i);
19: }
20: else
21: done = true;
22: }
23: cout << “Global x = “ << ::x <<>
24: cout <<>
25: getch();
s
NEW TERM
continues
54 Day 2
26: return 0;
27: }
28: void CountLoops(int x)
29: {
30: cout << “, While loop has executed “
31: <<>
32: }
The first thing you might notice (if you’re still awake by this time) is that the variable x is
declared four times. It is declared on line 4 outside the main() function, on line 8 inside the
main() function, on line 13 inside the while loop, and in the CountLoops() function on line
28. If you accidentally declare a variable more than once, the compiler spits out an error that
says Multiple declaration for ‘x’ and the compile stops. Yet this program compiles and
runs just fine. Why? Because each of the x variables in Listing 2.3 is in a different scope.
Take a closer look at Listing 2.3. The declaration for x on line 13 is inside the body of the
while loop and is local to that block of code. Effectively, it does not exist outside that block.
This variable has local scope. Likewise, the declaration for x on line 28 is local to the
CountLoops() function and does not exist outside the function. In this case the declaration
for x is less obvious because it’s part of the function’s parameter list, but it’s a variable
declaration nonetheless.
Now look at the variables x and i declared inside the main() function. These variables are local
to the code block in which they are declared, plus they are available (in scope) in any code
blocks within the code block in which they are declared. In other words, the x and i variables
are in scope both in the main() function and inside the while loop. That’s easy enough to
figure out in the case of i because there is only one variable named i. But what about x? Once
inside the while loop, there are two variables named x (the one declared in main() and the
one declared in the while loop), and both are in scope. Which one is being used? The one
within the while loop, because it has the most immediate scope.
A recent C++ draft rule change affects the visibility of a variable that is
declared inside a statement like a for statement. (The C++ draft is a
document that the C++ standards committee issues. It defines the rules
for the C++ language.) For example, the following code will generate a
compiler error:
for (int i=0;i<10;i++)>
if (array[i] == 40) break;
}
index = i;
Listing 2.3. continued
NOTE
Wading In Deeper 55
2
This code generates a compiler error because the variable i is visible
only inside the for loop code block. In order to get this code to
compile, you would have to declare i outside the for statement:
int i;
for (i=0;i<10;i++)>
if (array[i] == 40) break;
}
index = i;
Although this change won’t affect you if you are just learning C++, it
threw many old C++ programmers for a loop when it was first announced.
In the end, it doesn’t really matter which form is the standard
as long as we programmers know what the rules are.
Finally, we get to the declaration of the x that falls outside the main() function (line 4).
Because this variable is declared outside any function, it is called a global variable and is said
to have global scope. What this means is that the global variable x is available anywhere in the
program: inside the main() function, inside the while block, and inside the CountLoops()
function.
As mentioned earlier, a local variable will have precedence over a global variable. But what
if you want to access the global variable x from inside the main() function? You use the scoperesolution
operator, ::. Line 23 of Listing 2.3 contains this line:
cout << “Global x = “ << ::x <<>
The scope-resolution operator tells the compiler, “Give me the global variable x and not the
local variable x.” (The scope-resolution operator is also used with classes, but I’ll get to that
when I talk about classes later.)
extern Variables
A real-world application usually has several source files containing the program’s code. (The
terms module, source file, and unit can be used interchangeably. I’ll talk about programs using
multiple source files in just a bit.) A global variable declared in one source file is global to that
file but is not visible in any other modules. There are times, however, when you need to make
a variable visible to all modules in your program. Doing this is a two-step process. First,
declare the variable in one source file as you would any global variable. Then, in any other
source file that needs to access the global variable, you declare the variable again, this time
with the extern keyword:
extern int countChickens;
56 Day 2
The extern keyword tells the compiler, “I’m going to be using a variable in this source file
that you will find declared in another source file.” The compiler sorts it all out at compile time
and makes sure you get access to the correct variable.
While global variables are convenient, they aren’t particularly OOP friendly. Usually there
are better solutions (which you will learn about when I discuss classes). In addition, global
variables consume memory for the life of the program. Local variables use up memory only
while they are in scope. Use local variables whenever possible, and keep the use of global
variables to a minimum.
Structures
A structure is a collection of related data rolled up into a single storage unit. For instance, let’s
say you wanted to keep a mailing list. It would be convenient to be able to have a single data
variable that could be used to hold all the fields needed in a typical mailing list. A structure
will allow you to do that. You first declare a structure and then later create an instance of that
structure when you want to put the structure to use. A structure is declared with the struct
keyword:
struct mailingListRecord {
char firstName[20];
char lastName[20];
char address[50];
char city[20];
char state[4];
int zip;
bool aFriend;
bool aFoe;
};
Each of the elements of a structure is called a data member. You will notice that each of the
data members must be declared just as it would be if it were a variable in a code block. In this
example I have five char arrays, one int, and two bool data members. (My apologies to my
friends around the world if this looks like a U.S.-slanted mailing-list record.) Finally, make
note of the semicolon following the closing brace of the structure declaration. This is a
requirement for structure and class declarations.
A structure is a collection of related data identified as a single storage unit. After a
structure has been declared, an instance of that structure can be created for use. Each
of the elements of a structure is called a data member.
NEW TERM
Wading In Deeper 57
2
You can create instances of a structure when you declare the structure.
At the end of the structure declaration, insert a variable name (one or
more) between the closing brace and the semicolon that follows the
structure declaration. Here’s an example:
struct point {
int x;
int y;
} upperLeft, lowerRight;
This code declares the structure and creates two instances of the
structure with variable names upperLeft and lowerRight.
Now that I have the structure declared, I need to put it to use. I first need to create an instance
of the structure. Here’s how that looks:
mailingListRecord record;
This statement allocates memory for the structure (120 bytes, give or take) and assigns that
memory to a variable named record. Now that I have an instance of the structure set up, I
can assign values to the data members:
strcpy(record.firstName, “Bruce”);
strcpy(record.lastName, “Reisdorph”);
strcpy(record.address, “123 Inspiration Pt.”);
strcpy(record.city, “Merced”);
strcpy(record.state, “CA”);
record.zip = 95031;
record.aFriend = true;
record.aFoe = false;
There is something you haven’t seen yet in this code. In order to access the data members of
a structure, you need to employ the structure member operator, which is a period placed
between the variable name and the data member. (If you forget to add the structure member
operator, you will probably have the compiler whining about undefined symbols.) The
structure member operator allows you to access a particular member of the structure—either
to read the value of the data member or to change the value of the data member.
If you want to, you can instantiate an object and supply its members all at one time:
mailingListRecord rec = {
“Bruce”,
“Reisdorph”,
“123 Inspiration Pt.”,
“Merced”,
“CA”,
95031,
true,
false
};
NOTE
58 Day 2
This saves you some typing over the first method I showed you, but is not always practical
in real-world situations. In a real-world program a structure would likely be filled out as a
result of user input or possibly with data read from a file. Assigning data to the structure like
you see here is not practical in those situations.
The struct statement:
struct name {
data_member_1;
data_member_2;
.
.
.
data_member_n;
} instance;
The struct statement declares a grouping of data members (data_member_1, data_member_2,
…, data_member_n) and provides a name for this grouping (name). The optional instance
statement creates an occurrence of this grouping.
Arrays of Structures
Just as you can have arrays of ints, chars, or longs, you can also have arrays of structures.
Declaring and using an array of structures is not terribly complicated:
mailingListRecord listArray[5];
strcpy(listArray[0].firstName, “Chuck”);
listArray[4].aFoe = true; // grrrrr!!
// etc.
This is only slightly more complicated than using an array of one of the integral data types.
You will notice that the subscript operator and the structure member operator are used backto-
back.
Headers and Source Files
The source file is an ASCII text file that contains the program’s source code. The compiler
takes the source code file, parses it, and produces machine language that the computer can
execute.
One of the problems with books on programming is that they use simple examples to
communicate concepts and ideas. You will undoubtedly find that things are never that
simple. So far, we have been dealing with very short programs contained in a single source
file. In the real world, a program of any consequence will have several source files. A program’s
code is divided into different source files for a number of reasons. One of the primary reasons
is organization. By keeping related chunks of code together, you can more easily find a certain
section of code when needed.
SYNTAX
t
s
Wading In Deeper 59
2
So how do the source files all get tied together? First, the compiler compiles each source file
(.cpp) into an object file (.obj). After each module has been compiled, the linker links all the
object files together to make a single executable file (the .exe). The linker also may link in
other needed files such as resource files (.res) and library files (.lib).
The declarations for classes and structures are often kept in a separate file called a
header file. Headers have a filename extension of .h or .hpp. (I touched on headers
briefly when I discussed the iostream class in Day 1, “Getting Your Feet Wet.”) A header file
should contain only class, structure, and function declarations. You should never put any
code statements in a header.
There is an exception to the rule that no code should be placed in
headers. You may put inline functions in headers. An inline function is a
special function in terms of the way the compiler generates code for the
function. You’ll learn more about inline functions on Day 4, “Totally
Immersed: C++ Classes and Object-Oriented Programming,” when I
discuss classes.
Once you have created a header file for a class or structure, you can include that header in
any source code module that needs to see the class or structure declaration. To do that you
use the #include directive:
#include “structur.h”
When you use the #include directive, it is as if the contents of the file being included
were pasted into the source file at that point. Listing 2.4, in the next section, contains a
program that uses the #include directive. The header file used in Listing 2.4 is contained in
Listing 2.5.
Header files typically implement a sentry to ensure that the header is
included only once for a program. A sentry essentially tells the compiler,
“I’ve already been included once, so don’t include me again.” A
sentry looks like this:
#ifndef _MYCLASS_H
#define _MYCLASS_H
class MyClass {
// class declared here
};
#endif
NEW TERM
NOTE
TIP
60 Day 2
C++Builder automatically adds sentries to units that you create as a
result of creating new forms or components. You should add sentries to
any headers you create for classes used outside the C++Builder VCL
framework.
A header file can contain more than one class or structure declaration. Using a separate header
for each class or structure helps keep your project organized and makes it easier to reuse classes
and structures in other programs. Sometimes you will group related classes together in one
header. For instance, you may have a class that implements a helper class to carry out its
duties. In that case, both the main class and the helper class would be declared in the same
header. Ultimately, it’s up to you how you organize your headers.
Don’t be too concerned if this is all a little fuzzy right now. It will probably take some
experience writing real programs for all this to come together for you.
An Example Using Structures
Listing 2.4 contains a program that has the user input three names and addresses and stores
those records in an array of structures. After the names are input, they are displayed on the
screen. The user is asked to choose one of the records. When the user chooses one of
the records, it is displayed on the screen. Listing 2.5 contains the header file for the
mailingListRecord structure used in the MAILLIST program shown in Listing 2.4.
Listing 2.4. MAILLIST.CPP.
1: #include
2: #include
3: #include
4: #pragma hdrstop
5: #include “structur.h”
6: void displayRecord(int, mailingListRecord mlRec);
7: int main(int, char**)
8: {
9: //
10: // create an array of mailingListRecord structures
11: //
12: mailingListRecord listArray[3];
13: cout <<>
14: int index = 0;
15: // get three records
16: //
17: do {
18: cout << “First Name: “;
19: cin.getline(listArray[index].firstName,
Wading In Deeper 61
2
20: sizeof(listArray[index].firstName) - 1);
21: cout << “Last Name: “;
22: cin.getline(listArray[index].lastName,
23: sizeof(listArray[index].lastName) - 1);
24: cout << “Address: “;
25: cin.getline(listArray[index].address,
26: sizeof(listArray[index].address) - 1);
27: cout << “City: “;
28: cin.getline(listArray[index].city,
29: sizeof(listArray[index].city) - 1);
30: cout << “State: “;
31: cin.getline(listArray[index].state,
32: sizeof(listArray[index].state) - 1);
33: char buff[10];
34: cout << “Zip: “;
35: cin.getline(buff, sizeof(buff) - 1);
36: listArray[index].zip = atoi(buff);
37: index++;
38: cout <<>
39: }
40: while (index <>
41: //
42: // clear the screen
43: //
44: clrscr();
45: //
46: // display the three records
47: //
48: for (int i=0;i<3;i++)>
49: displayRecord(i, listArray[i]);
50: }
51: //
52: // ask the user to choose a record
53: //
54: cout << “Choose a record: “;
55: char rec;
56: //
57: // be sure only 1, 2, or 3 was selected
58: //
59: do {
60: rec = getch();
61: rec -= 49;
62: } while (rec <> 2);
63: //
64: // assign the selected record to a temporary variable
65: //
66: mailingListRecord temp = listArray[rec];
67: clrscr();
68: cout <<>
69: //
70: // display the selected record
71: //
72: displayRecord(rec, temp);
73: getch();
74: return 0;
continues
62 Day 2
75: }
76: void displayRecord(int num, mailingListRecord mlRec)
77: {
78: cout << “Record “ <<>
79: cout << “Name: “ <<>
80: cout <<>
81: cout <<>
82: cout << “Address: “ <<>
83: cout <<>
84: cout <<>
85: cout <<>
86: cout <<>
87: cout <<>
88: }
Listing 2.5. STRUCTUR.H.
1: #ifndef _STRUCTUR_H
2: #define _STRUCTUR.H
3: struct mailingListRecord {
4: char firstName[20];
5: char lastName[20];
6: char address[50];
7: char city[20];
8: char state[5];
9: int zip;
10: };
11: #endif
There are a couple new things presented in this program and some variations on material
we’ve already covered.
First, this program uses the getline() function of the cin class to get input from the user (on
line 19, for instance). I did this because the cin extraction operator, >>, is not very friendly
when it comes to whitespace. The second parameter of getline() is used to limit the number
of characters that will be placed in the buffer (in this case the buffer is a data member of the
mailingListRecord structure). I supply a value here because I don’t want to overwrite the end
of the arrays in the structure. The sizeof() operator is used to determine the size of the
destination buffer so we know how many characters we can safely store in the buffer.
The atoi() function on line 36 is also new to you. This function takes a character string and
converts it to an integer value. This is necessary to convert the text in the zip code field (which
I got from the user as a string) to an integer value that can be stored in the zip data member
of the mailingListRecord structure.
Listing 2.4. continued
Wading In Deeper 63
2
The displayRecord() function, which begins on line 76, takes two parameters. The first
parameter, num, is an int that contains the index number of the record to display. This variable
is used only to display the record number. On line 78 I add 1 to num when I display it because
users are accustomed to lists beginning with 1 rather than with 0. (I aim to please!) The second
parameter of the displayRecord() function is an instance of the mailingListRecord structure.
Inside the displayRecord() function I use the local instance of the structure passed in
(which represents a copy of the structure) to display the contents of the structure.
In this case I am passing the mailingListRecord structure by value.
What this means is that a copy of the structure is created each time the
displayRecord() function is called. This is not very efficient because of
the overhead required to pass a structure by value. The overhead comes
in the form of the extra time and memory required to make a copy of
the structure each time the function is called. It would be better to
pass the structure by reference, but I haven’t talked about that yet,
because the structure is passed by value in this program. You will
learn about passing by reference tomorrow when we discuss functions
in C++.
Note that the displayRecord() function is called from both the for loop when all the records
are displayed (line 49) and again from the main body of the program to display the actual
record chosen (line 72). That’s precisely why the code to display a record has been placed in
a function. By putting it in a function, I only have to write the code once and can avoid
duplicating the code unnecessarily.
Any time you find yourself repeating code more than a couple times in
your programs, think about moving that code to a function. Then you
can call the function when you need that code executed.
There is another segment of this program that deserves mention. Look at this do-while loop,
which begins on line 59:
do {
rec = getch();
rec -= 49;
} while (rec <> 2);
This code first gets a character from the keyboard using the getch() function. As you have
TIP
NOTE
64 Day 2
seen, I have been using getch() at the end of my programs to keep the program from closing
prematurely, but have been ignoring the return value. The getch() function returns the
ASCII value of the key pressed. Because the ASCII value of the 1 key is 49, I want to subtract
49 from the value of the key pressed to obtain the equivalent index number for that record
in the records array. If the user presses 1, an ASCII 49 is returned, and 49–49 is 0, which
is the first index of the array. If the user presses 2, the calculation yields 1 (50–49), and so on.
The do-while loop ensures that the user presses a key between 1 and 3. If a key other than
1, 2, or 3 is pressed, the loop continues to fetch keystrokes until a valid key is pressed.
Finally, I want to point out line 66 in Listing 2.4:
mailingListRecord temp = listArray[rec];
This code is not necessary in this program, but I included it to illustrate a point. This code
creates an instance of the mailingListRecord structure and assigns to it the contents of one
of the structures in the array. A simple assignment is possible here because the compiler knows
how to copy one structure to another. It does a simple member-to-member copy and copies
all structure members to the newly created instance of the structure.
Our discussion of structures up to this point describes how a structure
works in C. In C++ a structure operates like it does in C, but C++
extends structures to allow them to contain functions as well as data
members. In fact, a structure in C++ is essentially a class where all data
members and functions have public access. That won’t make sense
until later on when I discuss classes on Day 4, but you can file this
tidbit away for future reference.
Now you know about structures. Chances are you won’t use a lot of structures in your
programs. This section is important, though, because it serves as sort of a primer for
discussing classes in Day 3, “Up to Your Neck in C++.”
Summary
This chapter contains essential information on some of C++’s basic operations. You need
what is presented here in order to program in C++Builder. First you learned about the
different types of loops in C++; then you learned about the switch statement and how to use
it. I talked a little about scope and what that means to your variables. Then you found out
what structures are and how they can be used in your programs. Tomorrow we’ll tackle some
of the big stuff.
NOTE
Wading In Deeper 65
2
Workshop
The Workshop contains quiz questions to help you solidify your understanding of the
material covered and exercises to provide you with experience in using what you have learned.
You can find answers to the quiz questions in Appendix A, “Answers to Quiz Questions.”
Q&A
Q How many levels deep can I nest if statements?
A There’s no limit. There is, however, a practical limit. If you have too many nested
if statements it gets very hard to keep all those brackets straight!
Q Will loops automatically terminate if something goes wrong?
A No. If you accidentally write an endless loop, that loop will continue to run until
you do something to stop it. You can stop a program stuck in an endless loop by
bringing up the Windows Task Manager (or the Close Program box) and ending
the errant task. If you executed the program via the C++Builder IDE, you can
choose Run | Reset Program from the main menu to kill the program.
Q Does a switch statement have to include a default section?
A No. The default section is optional.
Q Can I have more than one variable with the same name?
A Yes, provided they are in different scopes. You cannot have two variables named x
that are both declared within a code block. You can, however, have a global
variable named x and a local variable with the same name.
Q Can I use a structure by itself, without an object?
A No. Before you can use a structure you have to create an instance of the structure
and access the structure through the instance variable.
Quiz
1. What statements are executed in the event that an if expression evaluates to true?
2. What do the three parameters of a for statement represent?
3. Besides syntax, what is the difference between a while loop and a do-while loop?
4. What do the break and continue statements do?
5. What is a global variable?
6. Can a structure contain a mixture of data types (char, int, long, and so on)?
66 Day 2
7. How do you access the members of a structure?
8. Is it legal to have arrays of structures?
Exercises
1. Write a program that counts from 200 to 300 by 5s and displays the results.
2. Write a program that asks the user to input the day of the week and then displays
the name of the day using a switch statement.
3. See if you can figure out what the \b and \n do in this line from Listing 2.2:
cout << “\b!\nYipee!”;
Hint: Check the C++ Programmer’s Guide Help file for the section about escape
sequences.
4. Write a structure containing data members representing employee information.
Include first name, last name, address, hire date, and a data member indicating
whether the employee is in the company’s insurance plan.
Up to Your Neck in C++ 67
3
Up to Your Neck in C++
by Kent Reisdorph
“Don’t worry, I’ve got you.” Do you remember hearing those words when you
were learning to ride a bike? The C++ language is often unforgiving. With the
information in this chapter, you will be branching out into the concepts of C++
that most people trip over. Although I can’t promise to be there to pick you up
if you fall, I can at least point out some of the bumps in the road you might
encounter. Today you will learn about
n Pointers
n References
n The new and delete operators
n Functions in C++

No comments:
Post a Comment