Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ For Dummies (2004) [eng].pdf
Скачиваний:
84
Добавлен:
16.08.2013
Размер:
8.09 Mб
Скачать

112 Part II: Becoming a Functional C++ Programmer

//output the address of each variable

//in order to get an idea of how variables are

//laid out in memory

cout << “--- = 0x” << &end << “\n”; cout << “&n = 0x” << &n << “\n”; cout << “&l = 0x” << &l << “\n”; cout << “&f = 0x” << &f << “\n”;

cout << “&d = 0x” << &d << “\n”;

//wait until user is ready before terminating program

//to allow the user to see the program results system(“PAUSE”);

return 0;

}

The program declares a set of variables. It then applies the & operator to each one to find out where it lies in memory. The results of one execution of this program with Dev-C++ appear as follows:

--- = 0x0x22ff6c &n = 0x0x22ff68 &l = 0x0x22ff64

&f = 0x0x22ff60 &d = 0x0x22ff58

Press any key to continue . . .

Your results may vary. The absolute address of program variables depends on a lot of factors. In general, it may even vary from one execution of the pro­ gram to the next.

Notice how the variable n is exactly 4 bytes from the first variable declared (m2). The variable l appears 4 bytes down from that. The double variable d is a full 8 bytes from its neighboring variable f. Each variable has been allo­ cated just the space needed for its type.

There is no requirement that the C++ compiler pack variables in memory with no spaces between them. Dev-C++ could have laid out the variables in memory in any other reasonable fashion.

Using Pointer Variables

A pointer variable is a variable that contains an address, usually the address of another variable. Returning to my hotel analogy for a moment, I might tell my son that I will be in room 0x100 on my trip. My son is a pointer variable of sorts. Anyone can ask him at any time, “Where’s your father staying?” and he’ll spill his guts without hesitation.

Chapter 8: Taking a First Look at C++ Pointers 113

The following pseudo-C++ demonstrates how the two address operators shown in Table 8-1 are used:

mySon = &DadsRoom;

//

tell mySon the address of Dad’s Room

room = *mySon;

//

“Dad’s room number is”

The following C++ code snippet shows these operators used correctly:

void fn()

{

int intVar; int* pintVar;

pintVar = &intVar; // pintVar now points to intVar *pintVar = 10; // stores 10 into int location

// pointed at by pintVar

}

The function fn() begins with the declaration of intVar. The next statement declares the variable pintVar to be a variable of type pointer to an int. (By the way, pintVar is pronounced pee-int-Var, not pint-Var.)

Pointer variables are declared like normal variables except for the addition of the unary * character. This * character can appear anywhere between the base type name — in this case int — and the variable name; however, it is becoming increasingly common to add the * to the end of the type.

The * character is called the asterisk character (that’s logical enough), but because asterisk is hard to say, many programmers have come to call it the splat character. Thus, they would say splat pintVar.

Many programmers adopt a naming convention in which the first character of the variable name indicates the type of the variable, such as n for int, d for double, and so on. A further aspect of this naming convention is to place a p at the beginning of a pointer variable name.

In an expression, the unary operator & means the address of. Thus, we would read the first assignment as store the address of intVar in pintVar.

To make this more concrete, assume that the memory for function fn() starts at location 0x100. In addition, assume that intVar is at address 0x102 and that pintVar is at 0x106. The layout here is simpler than the actual results from the Layout program; however, the concepts are identical.

The first assignment stores the value of & intVar (0x102) in the pointer vari­ able pintVar. The second assignment in the small program snippet says “store 10 in the location pointed at by pintVar.” The value 10 is stored in the address contained in pintVar, which is 0x102 (the address of intVar).

114 Part II: Becoming a Functional C++ Programmer

Comparing pointers and houses

A pointer is much like a house address. Your house has a unique address. Each byte in memory has an address that is unique. A house address is made up of both numbers and letters. For example, my address is 123 Main Street.

You can store a couch in the house at 123 Main Street — you can store a number in the byte located at 0x123456. Alternatively, you can take a piece of paper and write an address — I don’t know, say, 123 Main Street. You can now store a couch at the house with the address written on the piece of paper. In fact, this is the way delivery people work — their job is to deliver a couch to the address written down on the shipping orders whether it’s 123 Main Street or not. (I’m not maligning delivery people — they have brains — it’s just that this is more or less the way things work.)

In C++, the following code snippet finds the address of myHouse and stores a couch at that houseAddress (loosely speaking):

House myHouse;

House* houseAddress;

houseAddress = &myHouse; *houseAddress = couch;

In humanspeak, you would say myHouse is a House. houseAddress is the address of a House. Assign the address of myHouse to the House pointer, houseAddress. Now store a couch at the house located at the address stored in houseAddress.

Having said all that, take a look at the int and int* version of the earlier example code snippet:

int myInt;

int* intAddress;

intAddress = &myInt; *intAddress = 10;

That is, myInt is an int. intAddress is a pointer to an int. Assign the address of myInt to the pointer intAddress. Finally, assign 10 to the int that intAddress points to.

Using different types of pointers

Every expression has a type as well as a value. The type of the expression intVar is pointer to an integer, written as int*. Comparing this with the dec­ laration of pintVar, you see that the types match exactly:

int* pintVar = &intVar; // both sides of the assignment are

// of type int*

Chapter 8: Taking a First Look at C++ Pointers 115

Similarly, because pintVar is of type int*, the type of *pintVar is int:

*pintVar = 10; // both sides of the assignment are

// of type int

The type of the thing pointed to by pintVar is int. This is equivalent to saying that, if houseAddress is the address of a house, the thing pointed at by houseAddress must be a house. Amazing, but true.

Pointers to other types of variables are expressed the same way:

double doubleVar;

double* pdoubleVar = &doubleVar; *pdoubleVar = 10.0;

A pointer on a Pentium class machine takes 4 bytes no matter what it points to. That is, an address on a Pentium is 4 bytes long, period.

Matching pointer types is extremely important. Consider what might happen if the following were allowed:

int n1; int* pintVar;

pintVar = &n1; *pintVar = 100.0;

The second assignment attempts to store the 8-byte double value 100.0 into the 4-byte space allocated for n1. Actually, this isn’t as bad as it looks — C++ is smart enough to demote the constant 100.0 to an int before making the assignment.

It is possible to cast one type of variable into another:

int iVar;

double dVar = 10.0; iVar = (int)dVar;

Similarly, it is possible to cast one pointer type into another.

int* piVar;

double dVar = 10.0;

double* pdVar; piVar = (int*)pdVar;

Consider, however, what catastrophes can arise if this type of casting about of pointers were to get loose. Save a variable into an area of the wrong size, and nearby variables can be wiped out. This is demonstrated graphically in the following LayoutError program.

116 Part II: Becoming a Functional C++ Programmer

// LayoutError - demonstrate the results of // a messing up a pointer usage #include <cstdio>

#include <cstdlib> #include <iostream> using namespace std;

int main(int nNumberofArgs, char* pszArgs[])

{

int

upper = 0;

int

n

= 0;

int

lower = 0;

// output the values of the three variables before...

cout << “the initial values are” << endl; cout << “upper = “ << upper << endl; cout << “n = “ << n << endl; cout << “lower = “ << lower << endl;

//now store a double into the space

//allocated for an int

cout << “\nStoring 13.0 into the location &n” << endl; double* pD = (double*)&n;

*pD = 13.0;

// display the results

cout << “\nThe final results are:” << endl; cout << “upper = “ << upper << endl;

cout << “n = “ << n << endl; cout << “lower = “ << lower << endl;

//wait until user is ready before terminating program

//to allow the user to see the program results system(“PAUSE”);

return 0;

}

The first three lines in main() declare three integers in the normal fashion. The assumption made here is that these three variables are laid out next to each other.

The next three executable lines output the value of the three variables. Not surprisingly, all three variables display as 0. The assignment *pD = 13.0; stores the double value 13.0 in the integer variable n. The three output state­ ments display the values of all three variables after the assignment.

After assigning the double value 13.0 in the integer variable n, n is not modi­ fied at all; however, the nearby variable upper is filled with a garbage value. This is not good, as the output from the program shows:

the initial values are

upper = 0