Thursday, September 3, 2009

how to write Windows programs in C++.

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 Loop

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+Del and kill the task. The

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 Loop

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