0% found this document useful (0 votes)
13 views42 pages

CH 12 - C++ Programming - DSMalik - 8e - 2018-Text

Chapter 12 edition 8

Uploaded by

fa23-bsm-040
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views42 pages

CH 12 - C++ Programming - DSMalik - 8e - 2018-Text

Chapter 12 edition 8

Uploaded by

fa23-bsm-040
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 42

818 | Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

In Chapter 2, you learned that C11’s data types are classified into three categories:
simple, structured, and pointers. Until now, you have studied only the first two data
types. This chapter discusses the third data type called the pointer data type. You will
first learn how to declare pointer variables (or pointers, for short) and manipulate the
data to which they point. Later, you will use these concepts when you study dynamic
arrays and linked lists. Linked lists are discussed in Chapter 17.

Pointer Data Type and Pointer Variables


Chapter 2 defined a data type as a set of values together with a set of operations.
Recall that the set of values is called the domain of the data type. In addition to these
two properties, until now, all of the data types you have encountered have one more
thing associated with them: the name of the data type. For example, there is a data
type called int. The set of values belonging to this data type includes integers that
range between –2147483648 and 2147483647, and the operations allowed on these
values are the arithmetic operators described in Chapter 2. To manipulate numeric
integer data in the range –2147483648 to 2147483647, you can declare variables using
the word int. The name of the data type allows you to declare a variable of that type.
Next, we describe the pointer data type.
The values belonging to pointer data types are the memory addresses of your computer. As
in many other languages, there is no name associated with the pointer data type in C11.
Because the domain—that is, the set of values of a pointer data type—is the addresses
(locations) in memory, a pointer variable is a variable whose content is an address, that
is, a memory location and the pointer variable is said to point to that memory location.
Pointer variable: A variable whose content is an address (that is, a memory address)
and is therefore said to point to a memory address.

Declaring Pointer Variables


As remarked previously, there is no name associated with pointer data types. More-
over, pointer variables store memory addresses. So the obvious question is: If no
name is associated with a pointer data type, how do you declare pointer variables?
The value of a pointer variable is an address or memory space that typically contains
some data. Therefore, when you declare a pointer variable, you also specify the data
type of the value to be stored in the memory location pointed to by the pointer variable.
For example, if a pointer variable contains the address of a memory location contain-
ing an int value, it is said to be an int pointer or a pointer (variable) of type int. As
with regular variables, pointers are bound to a data type and they can only contain the
addresses of (or point to) variables of the specific data type they were created to hold.
In C11, you declare a pointer variable by using the asterisk symbol (*) between the
data type and the variable name. The general syntax to declare a pointer variable is:

dataType *identifier;

Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
Pointer Data Type and Pointer Variables | 819

As an example, consider the following statements:


int *p;
char *ch;

In these statements, both p and ch are pointer variables. The content of p (when
properly assigned) points to a memory location of type int, and the content of ch
points to a memory location of type char. So, p is a pointer variable of type int, and
ch is a pointer variable of type char.

Before discussing how pointers work, let us make the following observations. The
statement:
int *p;

is equivalent to the statement:


int* p;

which is equivalent to the statement:


int * p;

Thus, the character * can appear anywhere between the data type name and the
variable name.
Now, consider the following statement:
int* p, q;

In this statement, only p is the pointer variable, not q. Here, q is an int variable. Each
variable must have its own * character placed to the left of it to make it a pointer vari-
able. To avoid confusion, we prefer to attach the character * to the variable name. So
the preceding statement is written as:
int *p, q;

Of course, the statement:


int *p, *q;

declares both p and q to be pointer variables of type int.


1
2
Now that you know how to declare pointers, next we will discuss how to make a
pointer point to a memory space and how to manipulate the data stored in these
memory locations.
Because the value of a pointer is a memory address, a pointer can store the address of
a memory space of the designated type. For example, if p is a pointer of type int, p can
store the address of any memory space of type int. C11 provides two operators—
the address of operator (&) and the dereferencing operator (*)—to work with point-
ers. The next two sections describe these operators.

Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
820 | Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

Address of Operator (&)


In C11, the ampersand, &, called the address of operator, is a unary operator that
returns the address of its operand. For example, given the statements:
int x;
int *p;
the statement:
p = &x;

assigns the address of x to p. That is, x and the value of p refer to the same memory
location.
Let’s compare names and pointers. In the following two declarations, num1 and num2
are int variables and numPtr is the name of an int pointer:
int num1, num2;
int *numPtr;
The name num1 now stands in place of an int memory location and can be assigned
the value of any integer between –2147483648 and 2147483647. For example, the
­following statement stores 100 in num1:
num1 = 100;

The value held at the memory location named num1 can easily be copied directly to
another integer memory location by using the assignment operator. For instance, if
we want to copy the integer 100 at the memory location num1 to the memory location
num2, we can use this statement:
num2 = num1;

The name num1 in a sense means “the value held in the memory location named
num1.” This value is copied into the memory location named num2.
On the other hand, when we use the statement:
numPtr = &num1;

we are asking the program to copy the address of the memory location of num1 to
numPtr, not the integer value it is holding. The pointer numPtr will not contain 100,
but the actual address num1 has been assigned by the operating system. (In a sense,
since the name num1 stands for the memory address of num1’s value, and numPtr con-
tains the address of num1, numPtr is really holding the name num1. This makes numPtr
a reference to num1.)
Now, if we output both num1 and numPtr using the statements
cout << num1 << endl;
cout << numPtr << endl;

Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
Dereferenclng Operator (* ) I 821

the first line will output 1 00 onto the sc reen, while the second line will output an
address usually displayed in hexadecimal d igits.
In the next sectio n, after discussing the dereference o perator, we will explain how to
output the value of the memory location whose address is sto red in nwnPtr.

Dereferencing Operator (*)


Every chapte r until now has used the asterisk character, *, as the binary multiplica-
tio n operato r. c+ + also uses · as a unary operator. When used as a unary operator, . ,
commo nly referred to as the dereferencing operator or indirection operator, refers
to the object to which its operand (that is, the pointer) points. For example, given the
statements:
1nt x=25;
1nt ·p l
p = &XI //store the address of x in p
the statement
cou t « .p « end1;

prints the value stored in the memory space pointed to by p, which is the value of x.
Also, the statement
*p = 55 ;
stores 55 in the memory location pointed to by p - that is, in x .

Le t us consider the fo llowing statements:


1nt .p;
1nt nUll'l;

In these state ments, p is a pointer variable of type int, and nwn is a var iable of type
1nt. Let us assume that memory location 1200 is allocated for p, and memory loca-
tion 18 00 is allocated for num. (See Figure 1 2-1.)

1200 1800
P n=

fiGURE 12·1 Varlabi@Spandnum


822 | Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

Consider the following statements:


1. num = 78;
2. p = &num;
3. *p = 24;

The following shows the values of the variables after the execution of each statement.

After
Statement Values of the Variables Explanation

1. The statement num = 78; stores 78


. . . . . . 78 . . .
into num.
1200 1800
p num

2. The statement p = &num; stores


. . . 1800 . . . 78 . . .
the address of num, which is 1800,
1200 1800 into p.
p num

3. The statement *p = 24; stores 24


. . . 1800 . . . 24 . . .
into the memory location to which p
1200 1800 points. Because the value of p is 1800,
p num statement 3 stores 24 into memory
location 1800. Note that the value of
num is also changed.

Let us summarize the preceding discussion.


1. A declaration such as int *p; allocates memory for p only, not for *p.
Later, you will learn how to allocate memory for *p.
2. The content of p points only to a memory location of type int.
3. &p, p, and *p all have different meanings.
4. &p means the address of p—that is, 1200 (in Figure 12-1).
5. p means the content of p, which is 1800, after the statement
p = &num; executes.
6. *p means the content of the memory location to which p points. Note
that after the statement p = &num; executes, the value of *p is 78; after
the statement *p = 24; executes, the value of *p is 24.

Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
Dereferenclng Operator (* ) I 823

Consider the following statements:


tnt *p ;
tnt x;
Suppose that we have the memo ry allocation for p and x as show n in Figure 12-2.

I· 1400 17.50
·1
P x

FIGURE 12·2 Variables p and x

The values of Gop, p , *p, &x, and x are as follows:

&P E:::J p I ? (unknown)


I_*p L'-
....O"'. . ,'O'_
(undefined)
~ x I?
',;'_'_ --' ~
&X
.
(unknown)

Suppose that the fo llowing statements are executed in the o rder given:
x = 50 ;
P = "X;
*p = 38;
The values of &P, p , .p, "-X, and x are s hown after each of these state ments executes.
After the state ment x = 50; executes, the values of "p, p, *p, "-X, and x are as follows:

"P E:::J p I?(unknown)


I
.
*p L~(undefined)
- =~oo~,=,~,_;,_,_-' &x ~
~
x LJ
rsol
After the statement p = &x; executes, the values of Gop, p, *p, &X, and x are as follows:

&P 114 00

After the statement *p = 38; executes, the values of &P, p, *p, &x, and x are as
follows: (Because *p and x refer to the same memory space, the value of x is also
changed to 38.)

&P 114 00 P 11 750 &X11750


824 | Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

Let us note the following:


1. p is a pointer variable.
2. The content of p points only to a memory location of type int.
3. Memory location x exists and is of type int. Therefore, the assignment
statement:
p = &x;
is legal. After this assignment statement executes, *p is valid and
meaningful.

The program in Example 12-3 further illustrates how a pointer variable works.

E X AMPL E 12-3

The following program illustrates how pointer variables work:


//Chapter 12: Example 12-3

#include <iostream> //Line 1


#include <iomanip> //Line 2

using namespace std; //Line 3

const double PI = 3.1416; //Line 4

int main() //Line 5


{ //Line 6
double radius; //Line 7
double *radiusPtr; //Line 8

cout << fixed << showpoint << setprecision(2); //Line 9

radius = 2.5; //Line 10


radiusPtr = &radius; //Line 11

cout << "Line 12: Radius = " << radius


<< ", area = " << PI * radius * radius
<< endl; //Line 12

cout << "Line 13: Radius = " << *radiusPtr


<< ", area = "
<< PI * (*radiusPtr) * (*radiusPtr)
<< endl; //Line 13

cout << "Line 14: Enter the radius: "; //Line 14


cin >> *radiusPtr; //Line 15
cout << endl; //Line 16

Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
Dereferencing Operator (*) | 825

cout << "Line 17: Radius = " << radius << ", area = "
<< PI * radius * radius << endl; //Line 17
cout << "Line 18: Radius = " << *radiusPtr
<< ", area = "
<< PI * (*radiusPtr) * (*radiusPtr) << endl
<< endl; //Line 18

cout << "Line 19: Address of radiusPtr: "


<< &radiusPtr << endl; //Line 19
cout << "Line 20: Value stored in radiusPtr: "
<< radiusPtr << endl; //Line 20
cout << "Line 21: Address of radius: "
<< &radius << endl; //Line 21
cout << "Line 22: Value stored in radius: "
<< radius << endl; //Line 22

return 0; //Line 23
} //Line 24

Sample Run: In this sample run, the user input is shaded.


Line 12: Radius = 2.50, area = 19.64
Line 13: Radius = 2.50, area = 19.64
Line 14: Enter the radius: 4.90

Line 17: Radius = 4.90, area = 75.43


Line 18: Radius = 4.90, area = 75.43

Line 19: Address of radiusPtr: 013EFDA4


Line 20: Value stored in radiusPtr: 013EFDB0
Line 21: Address of radius: 013EFDB0
Line 22: Value stored in radius: 4.90

The preceding program works as follows. The statement in Line 7 declares radius
to be a variable of type double and the statement in Line 8 declares radiusPtr to be
a pointer variable of type double. The statement in Line 10 stores 2.5 in radius and
the statement in Line 11 stores the address of radius in radiusPtr. The statement
in Line 12 outputs the radius and area of the circle using the value stored in the
memory location radius. The statement in Line 13 outputs the radius and area 1
of the circle using the value stored in the memory location to which radiusPtr
is pointing. Note that the output of the statements in Lines 12 and 13 is the same 2
because radiusPtr points to radius. Next, the statement in Line 14 prompts
the user to input the radius and the statement in Line 15 stores the radius in the
memory location to which radiusPtr is pointing. Next, similar to the statements in
Lines 12 and 13, the statements in Lines 17 and 18 output the radius and area using
the variables radius and radiusPtr. The statements in Lines 19 to 22 output the
address of radiusPtr, the value stored in radiusPtr, the address of radius, and
the value stored in radius.

Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
826 | Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

From the output of the statements in Lines 20 and 21, it follows that radiusPtr stores
the address of the variable radius. (Note that the address of radiusPtr, the value of
radiusPtr, and the address of radius as shown by the output of Lines 19, 20, and 21,
respectively, are machine dependent. When you run this program on your machine,
you are likely to get different values. Furthermore, the pointer values, that is, the
addresses, are printed in hexadecimal by default.)

Classes, Structs, and Pointer Variables


In the previous section, you learned how to declare and manipulate pointers of simple
data types, such as int and char. You can also declare pointers to other data types,
such as classes. You will now learn how to declare and manipulate pointers to classes
and structs. (Recall that both classes and structs have the same capabilities. The only
difference between classes and structs is that, by default, all members of a class are
private, and, by default, all members of a struct are public. Therefore, the follow-
ing discussion applies to both.)
Consider the following declaration of a struct:
struct studentType
{
char name[26];
double gpa;
int sID;
char grade;
};

studentType student;
studentType* studentPtr;
In the preceding declaration, student is an object of type studentType, and
­ tudentPtr is a pointer variable of type studentType. The following statement
s
stores the address of student in studentPtr:
studentPtr = &student;

The following statement stores 3.9 in the component gpa of the object student:
(*studentPtr).gpa = 3.9;

The expression (*studentPtr).gpa is a mixture of pointer dereferencing and the


class component selection. In C11, the dot operator, ., has a higher precedence than
the dereferencing operator.
Let us elaborate on this a bit. In the expression (*studentPtr).gpa, the operator *
evaluates first, so the expression *studentPtr evaluates first. Because studentPtr
is a pointer variable of type studentType, *studentPtr refers to a memory space of
type studentType, which is a struct. Therefore, (*studentPtr).gpa refers to the
component gpa of that struct.

Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
Initializing Pointer Variables I 829

In the statement in Line 9, the pointer cExpPtr accesses the member fun ction satx
to set the value of the member variable x (see Figure 12-4).

cExpptr nl-- .

FIGURE 12-4 CExpObj act and cBxpPtr after the staterrM!nt cExpPtr _>sa tX (5); executes

In the statement in Line 10, the pointer c ExpPtr accesses the member function print
to print the value of x, as shown above.

Initializing Pointer Variables


Because C++ does not automatically initialize variables, pointer variables must be
initialized if you do not want them to point to anything. Pointer variables are initialized
using the constant value 0, called the null pointer. Thus, the statement p = 0; stores
the null pointer in p, that is, p points to nothing. Some programmers use the named
constant NOLL to initialize pointer variables. The named constant NOLL is defined in
the header file cstddef. The fo llowing two statements are equivalent:
p = NULL ;
P = 0;
The number 0 is the o nly number that can be directly assig ned to a poin ter variable.

Initializing Pointer Variables Using nullptr


c+ + 11 Standard provides the null pointer nullptr to initialize pointer variables.
A pointer with the value nullptr points to nothing, and is called the null po inter.
nullptr has a special value type that can be converted to any pointer type. The
following statement declares p to be a pointer of type int and it also initializes it to
the null pointer:
int *p = nullptr ;
Because the compiler that we have used to test the code has implemented this feature
ofC+ + II Standard, we can initialize the pointer variable using the int value 0, u sing
another po inter variable of the same type, or using nullptr. In C+ + , nullptr is a
reserved word.
830 | Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

Dynamic Variables
In the previous sections, you learned how to declare pointer variables, how to store
the address of a variable into a pointer variable of the same type as the variable, and
how to manipulate data using pointers. However, you learned how to use pointers to
Watch
the Video manipulate data only into memory spaces that were created using other variables. In
other words, the pointers manipulated data into already existing memory spaces. But
you could have accessed these memory spaces through the variables that were used
to create them. So what is the benefit of using pointers? In this section, you will learn
about the power behind pointers. In particular, you will learn how to allocate and
deallocate memory during program execution using pointers.
Variables that are created during program execution are called dynamic variables.
With the help of pointers, C11 creates dynamic variables. C11 provides two opera-
tors, new and delete, to create and destroy dynamic variables, respectively. When a
program requires a new variable, the operator new is used. When a program no lon-
ger needs a dynamic variable, the operator delete is used.
In C11, new and delete are reserved words.

Operator new
The operator new has two forms: one to allocate a single variable and another to allo-
cate an array of variables. The syntax to use the operator new is:

new dataType; //to allocate a single variable


new dataType[intExp]; //to allocate an array of variables

in which intExp is any expression evaluating to a positive integer.


The operator new allocates memory (as a variable) of the designated type and returns
a pointer to it—that is, the address of this allocated memory. Moreover, the allocated
memory is uninitialized.
Consider the following declaration:
int *p;
char *q;
int x;

The statement
p = &x;

stores the address of x in p. However, no new memory is allocated. On the other hand,
consider the following statement:
p = new int;

Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
Dynamic Va riables I 8 31

This statement creates a variable during program execut ion somewhere in memory
and stores the address of the allocated memory in p. The allocated memory is accessed
via pointer dereferencing- namely, *p. Similarly, the statement
q = new char [1 6 ] ;

creates an array of 1 6 components of type char and stores the base address of the
array in q.
Because a dynamic variable is unnamed, it cannot be accessed directly. It is accessed
indirectly by the pointer returned by new. The fo llowing statements illustrate this
concept:
int *p ; //p is a pointer of type int
char *name; //name is a pointer of type char
string * str ; //str is a pointer of type string

p = new int o //a11ocates memory of type int and stores


lithe address of the allocated memory in p
*p = 28; //stores 28 in the allocated memory

name = new char [ 5 ] ; //a11ocates memory for an array of five


//components of type char and stores the
//base address of the array in name
str c py ( name, "Jo hn" ); //stores John in name

str = new string ; //a11ocates memory of type string


//and stores the address of the
//a11ocated memory in str

* s tr = " Sunny Day" ; //stores tbe string ·Sunny Day· in


lithe memory pointed to by str

Recall that the operator new allocates memory space of a specific type and returns
the address of the allocated memory space. However, if the operator new is unable to
allocate the required memory space (for example, there is not enough memory space),
then it throws a bad_ a110c exception, and if this exception is not handled, it terminates
the program with an error message. Exceptions are covered in detail in Chapter 14. This
chapter also discusses bad _ a110c exception.

Operator delete
Suppose you have the fo llowing declaration:
int *p ;

This statement declares p to be a pointer variable of type int. Next, consider the
fo llowing statements:
p ~ new int o //Line 1
'p 54 ;
~ //Line 2
p ~ new int o //Line 3
'p 73 ;
~ //Line 4
Copyright 2018 Ceogagel"",m,ng. All Rights Rese<Ved. May oot be cOIIied. scanned, orduplicated, in wilDIe or in pan. WCN 02_200_203
832 I Chapter 12: Pointers, Classes, Virtual Functions, and A bstract Classes

Figure 12-5 shows the effect of these statements.

p~.

(a) p
___
1500

after the execution of


.1 P~
(b)
1500

p and *p after the


M I
p = new int i execution of *p = 54;

1800 1800

p~"-_...I P~ .. I
(c) p after the execution of (d) p and *p after the
p = new int i execution of *p = 73;

FIGURE 12-5 P after the memory space it points to following the execution of various statements

(The number 1500 on top of the box indicates the address of the memory space.)
The statement in Line 1 allocates memory space of type int and stores the address
of the allocated memory space into p. Suppose that the address of allocated memory
space is 1500. Then, the value of p after the execution of this statement is 1500 (see
Figure 12-5(a)) . The statement in Line 2 stores 54 into the memory space that p
points to, which is 1500 (see Figure 12-5(b)).
Next, the statement in Line 3 executes, which allocates a memory space of type iot
and stores the address of the allocated memory space into p. Suppose the address of
this allocated memory space is 1800. It follows that the value of p is now 1800 (see
Figure 12-5(c)). The statement in Line 4 stores 73 into the memory space that p points
to, which is 1800. In other words, after the execution of the statement in Line 4, the
value stored into memory space at location 1800 is 73 (see Figure 12-5(d)) .
Now the obvious question is what happened to the memory space 1500 that p was
pointing to after execution of the statement in Line L After execution of the statement
in Line 3, p points to the new memory space at location 1800. The previous memory
space at location 1500 is now inaccessible. In addition, the memory space 1500 remains
as marked allocated. In other words, it cannot be freed or reallocated. This is called
memory leak That is, there is an unused memory space that cannot be allocated.
Imagine what would happen if you executed statements, such as Line 3, a few thousand
or a few million times. There would be a good amount of memory leak. The program

Copyright 2018 Ceogagel"",m,ng. All Rights Rese<Ved. May oot be cOIIied, scanned, orduplicated, in wilDIe or in pan. WCN 02_200_203
Dynamic Variables | 833

might then run out of memory spaces for data manipulation, which would result in
an abnormal termination of the program.
The question at hand is how to avoid memory leak. When a dynamic variable is no
longer needed, it can be destroyed; that is, its memory can be deallocated. The C11
operator delete is used to destroy dynamic variables. The syntax to use the operator
delete has two forms:

delete pointerVariable; //to deallocate a single


//dynamic variable
delete [] pointerVariable; //to deallocate a dynamically
//created array

Thus, given the declarations of the previous section, the statements


delete p;
delete [] name;
delete str;
deallocate the memory spaces that the pointers p, name, and str point to.
Suppose p and name are pointer variables, as declared previously. Notice that an
expression such as
delete p;

or
delete [] name;

only marks the memory spaces that these pointer variables point to as deallocated.
Depending on the particular operating system, after these statements execute, these
pointer variables may still contain the addresses of the deallocated memory spaces.
In this case, we say that these pointers are dangling. Therefore, if later you access the
memory spaces via these pointers without properly initializing them, depending on
the particular system, either the program will access a wrong memory space, which
may result in corrupting data now stored in those spaces, or the program may ter-
minate with an error message. One way to avoid this pitfall is to set these pointers to
nullptr after the delete operation. Also note that for the operator delete to work
properly, the pointer must point to a valid memory space. 1
In Example 12-3, we used the pointer variable radiusPtr to access the memory loca- 2
tion of the variable radius. However, in that example, the radiusPtr pointed to an
existing memory, which was not created during program execution. In the following
example, we illustrate how to use the new and delete operators to allocate and deal-
locate dynamic memory.

Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
834 | Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

E X AMPL E 12-5

The following program illustrates how to use the operators new and delete.
//Program to illustrate how to use the operators new and delete.

#include <iostream> //Line 1


#include <iomanip> //Line 2

using namespace std; //Line 3

const double PI = 3.1416; //Line 4

int main() //Line 5


{ //Line 6
double *radiusPtr; //Line 7

cout << fixed << showpoint << setprecision(2); //Line 8

radiusPtr = new double; //Line 9

cout << "Line 10: Enter the radius: "; //Line 10


cin >> *radiusPtr; //Line 11
cout << endl; //Line 12

cout << "Line 13: Radius = " << *radiusPtr


<< ", area = " << PI * (*radiusPtr) * (*radiusPtr)
<< endl << endl; //Line 13

cout << "Line 14: Address of radiusPtr: "


<< &radiusPtr << endl; //Line 14
cout << "Line 15: Value stored in radiusPtr: "
<< radiusPtr << endl; //Line 15
cout << "Line 16: Value stored in the memory "
<< "location to which \n radiusPtr "
<< "is pointing: " << *radiusPtr << endl; //Line 16

delete radiusPtr; //Line 17

cout << "Line 18: After using the delete operator, "
<< "the value stored in the location\n "
<< "to which radiusPtr is pointing: "
<< *radiusPtr << endl; //Line 18

double *lengthPtr = new double; //Line 19

radiusPtr = new double; //Line 20

*radiusPtr = 5.38; //Line 21

cout << "Line 22: Address of radiusPtr: "


<< &radiusPtr << endl; //Line 22

Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
Operations on Pointer Variables | 835

cout << "Line 23: Value stored in radiusPtr: "


<< radiusPtr << endl; //Line 23
cout << "Line 24: Value stored in the memory "
<< "location to which radiusPtr is pointing: "
<< *radiusPtr << endl; //Line 24
cout << "Line 25: Value stored in lengthPtr: "
<< lengthPtr << endl; //Line 25

return 0; //Line 26
} //Line 27

Sample Run: In this sample run, the user input is shaded.


Line 10: Enter the radius: 4.50

Line 13: Radius = 4.50, area = 63.62

Line 14: Address of radiusPtr: 0093F9A0


Line 15: Value stored in radiusPtr: 00DE0230
Line 16: Value stored in the memory location to which
radiusPtr is pointing: 4.50
Line 20: Address of radiusPtr: 0093F9A0
Line 21: Value stored in radiusPtr: 00DE00A8
Line 22: Value stored in the memory location to which
radiusPtr is pointing: 5.38

For the most part, the preceding program is the same as the program in
Example 12-3. However, let us note the following: the statement in Line 9
allocates memory of type double and stores the address of the allocated memory
in radiusPtr. The output of the statement in Line 15 shows that the address of
the allocated memory is 00DE0230. Next the statement in Line 17 deallocates the
memory space to which radiusPtr is pointing. The statement in Line 20 allocates
(another) memory space of type double and stores the address of the allocated
memory space in radiusPtr, and the statement in Line 21 stores 5.38 in the
allocated memory space. The statements in Lines 23 to 25 output the addresses
as shown by the output. (Note that the addresses printed by this program are
machine dependent. When you run this program on your machine, you are likely
to get different values.) 1
2
Operations on Pointer Variables
The operations that are allowed on pointer variables are the assignment and rela-
tional operations and some limited arithmetic operations. The value of one pointer
variable can be assigned to another pointer variable of the same type.
For example, suppose that we have the following statements:
int *p, *q;

Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
836 | Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

The statement
p = q;

copies the value of q into p. After this statement executes, both p and q point to the
same memory location. Any changes made to *p automatically change the value of
*q, and vice versa.
Two pointer variables of the same type can be compared for equality, and so on. The
expression
p == q

evaluates to true if p and q have the same value—that is, if they point to the same
memory location. Similarly, the expression
p != q

evaluates to true if p and q point to different memory locations.


Integer values can be added and subtracted from a pointer variable. The value of
one pointer variable can be subtracted from another pointer variable. The arithmetic
operations that are allowed differ from the arithmetic operations on numbers. First,
let us use the following statements to explain the increment and decrement opera-
tions on pointer variables:
int *p;
double *q;
char *chPtr;
studentType *stdPtr;   //studentType is as defined before
Recall that the size of the memory allocated for an int variable is 4 bytes, a double
variable is 8 bytes, and a char variable is 1 byte. The memory allocated for a variable
of type studentType is then 40 bytes.
The statement
p++; or p = p + 1;

increments the value of p by 4 bytes because p is a pointer of type int. Similarly, the
statements
q++;
chPtr++;
increment the value of q by 8 bytes and the value of chPtr by 1 byte, respectively. The
statement
stdPtr++;

increments the value of stdPtr by 40 bytes.


The increment operator increments the value of a pointer variable by the size of the
data type or structure to which it is pointing. Similarly, the decrement operator decre-
ments the value of a pointer variable by the size of the data type or structure to which it
is pointing.
Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
Dynamic Arrays I 837

Moreover. the statement


p =p • 2i
increments the value o f p (an in t po inter) by B bytes.
T hus, when an integer is added to a po inter variable, the value of the po inter variable
is inc remented by the integer times the size of the data type o r structure to which the
pointer is pointing. Similarly, when an integer is s ubtracted fro m a po inter va riable,
the value of the po inter variable is decremented by the integer times the size of the
data type o r structu re to which the pointer is pointing.

Pointer arithmetic can be very dangerous. Using pointer arithmetic. the program can acci-
dentally access the memory locations of other variables and change their content without
warning. leaving the programmer trying to find out what went wrong. If a pointer variable
tries to access either the memory spaces of other variables or an illegal memory space,
some systems might terminate the program with an appropriate error message. Always
exercise extra care when doing pointer arithmetic.

Dynamic Arrays
In C hapter 8. you learned how to declare and process arrays. The arrays discussed in
Chapter 8 are called static arrays because t heir size was fixed at compile time. O ne o f
the limitations o f a static array is that every time you execute the program, the size of
the array is fLXed. so it might not be possible to use the same array to process differ-
ent data sets of t he same type. O ne way to handle this limitatio n is to declare an array
that is large enough to process a variety o f data sets. However, if the array is very big
and the data set is s mall, such a declaration would result in memo ry waste. O n the
other ha nd, it would be helpful if, during prog ram execution, you could pro mpt the
user to enter the size of the array and then create an array of the appropriate size. This
approach is especially helpful if you cannot even guess the array size. In this section,
you will learn how to create arrays during program execut io n and process such arrays.
An array created during the execution of a program is called a dynamic array. To
create a dy namic array, we use the second form of the new operator.
T he statement
int ·P i
declares P to be a pointer variable of type intoThe statement
p = new int [1 01i
allocates 10 contiguous memory locations, each of type int, and stores the address
ofthe first memory location into p. In other words, the o perator new creates an array
of 10 components o f type int , it returns the base address of the array. and t he assign-
ment operator sto res the base address o f t he array into p. T hus. the statement
.p = 2 S ;
838 I Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

stores 25 into the first memory location, and the statements:


p++; lip points to tbe next array component
"'p = 35;

store 35 into the second memory location. Thus, by using the increment and dec-
rement operations, you can access the components of the array. Of course, after
performing a few increment operations, it is possible to lose track of the first array
component. C+ + allows us to use array notation to access these memory locations.
For example, the statements
prO] = 25;
pill = 35;
store 25 and 35 into the first and second array components, respectively. That is,
p [0] refers to the first array component, p [1] refers to the second array component,
and so on. In general, p [i] refers to the (i + 1) th array component. Unlike using
pointer arithmetic, after the preceding statements execute, p still points to the first
array component. The following for loop initializes each array component to 0:
for ( int j = 0; j c 10; j++)
prj] = 0;

When the array notation is used to process the array pointed to by p, p stays fixed at
the first memory lo cation. Moreover, p is a dynamic array created during program
execution.

The statement:

int list [5];

declares lis t to be an array of five components of type into Recall from Chapter 8 that
lis t itself is a variable, and the value stored in lis t is the base address of the array-
that is, the address of the first array component. Suppose the address of the first array
component is 1000. Figure 12.6 shows list and the array list.

1 is t "''''''''-,

list[O]
list[l]
list[2]
list[3]
list[4]

FIGURE 12-6 list and array list


Copyright 2018 Ceogagel"",m,ng. All Rights Rese<Ved. May oot be cOIIied. scanned, orduplicated, in wilDIe or in pan. WCN 02_200_203
Dynamic Arrays I 839

Because the value of li st, which is 1 000, is a memory address, li s t is a pointer varia-
ble. However, the value stored in lis t, which is 1 000, caMot beaftered during program
execution. That is, the value of li st is constant. Therefore, the increment and decrement
operations cannot be applied to li s t. In fact, any attempt to use the increment or decre-
ment operations on li st results in a compile-time error.
Notice that here we are only saying that the value of li st cannot be changed. However,
the data in the array ~st can be manipulated as before. For example, the statement
li s t ( 0) = 25; stores 25 into the first array component. Similarly, the statement
li s t (J ) = 7 8; stores 78 into the fourth component of li s t (see Figure 12·7).

I is t "'''''"',

list[O)
list[l)
list[2)
list[3)
list[4)

FIGURE 12-7 Array li st after the execution of the statements li s t (01 = 2S; and
li st [3) = 78 ;

If p is a pointer variable of type int, then the statement

copies the value of li s t , which is 1000, the base address of the array, into p. Un~ke the
case with the name I i s t , we are allowed to perform increment and decrement operations
on the pointer p.
ArI array name is a constant pointer.

The fo llOWing program segment illust rates how to obtain a user's response to get
the array size and create a dynamic array during program execution. Consider the
fo llOWing statements:
int *intLi st; jjLine 1
int arrayS lz e; jjLine 2

cout « "En ter a rray s ize :


c i n » array Siz e;
., jjLine 3
jjLine 4
cout « endl ; jjLine 5

int Li s t = new int (a rrayS i ze ) ; jjLine 6


840 | Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

The statement in Line 1 declares intList to be a pointer of type int, and the
statement in Line 2 declares arraySize to be an int variable. The statement in Line 3
prompts the user to enter the size of the array, and the statement in Line 4 inputs the
array size into the variable arraySize. The statement in Line 6 creates an array of the
size specified by arraySize, and the base address of the array is stored in intList.
From this point on, you can treat intList just like any other array. For example, you
can use the array notation to process the elements of intList and pass intList as a
parameter to the function.

Arrays and Range-Based for Loops (Revisited)


Chapter 8 introduced range-based for loops, which is a feature of C1111 Standard,
and discussed how it can be effectively used to process the elements of an array. We
also pointed out that if a formal parameter of a function is an array, a range-based for
loop cannot be used on that formal parameter. In this section, we explain why this is
the case.
Consider the following statements:
int *list; //Line 1

list = new int[5]; //Line 2

for (int i = 0; i < 5; i++) //Line 3


list[i] = i * i; //Line 4

for (int x: list) //Line 5; illegal range-based for loop


cout << x << " "; //Line 6

The statement in Line 1 declares list to be a pointer variable of type int. During
execution, the statement in Line 2 creates an array of five components of type int and
stores the base address of the array into the pointer list. The statements in Lines 3
and 4 initialize the array to which list points. Now, the array to which list points is
a dynamic array. So at the compile time, the pointer list, even though it will contain
the base address of an array, has no first and no last elements. Therefore, in the for
loop in Line 5, x cannot be initialized to the first element of the array list. Thus, the
range-based for loop in Line 5 is illegal and will result in a syntax (compiler) error.
In essence, a range-based for loop cannot be used on dynamic arrays. The following
code shows the type of syntax errors generated by the compiler when a range-based
for loop is used on a dynamic array.
1. #include <iostream>
2.
3. using namespace std;
4.
5. int main()
6. {

Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
Dynamic Arrays | 841

7. int *list;
8.
9. list = new int[5];
10.
11. for (int i = 0; i < 5; i++)
12. list[i] = i * i;
13.
14. for (auto x : list)
15. cout << x << " ";
16. cout << endl;
17.
18. return 0;
19. }

Syntax errors generated by the compiler:


Ch12_Example_RangeBased_For_Loops.cpp
c:\ch12_example_rangebased_for_loops.cpp(15): error C3312: no
callable 'begin' function found for type 'int *'
­
c:\ch12_example_rangebased_for_loops.cpp(15): error C3312: no
callable 'end' function found for type 'int *'
­
c:\ch12_example_rangebased_for_loops.cpp(15): error C2065: 'x':
undeclared identifier
Note that in the previous programming code, the numbers on the left are not part
of the code. These numbers are merely to show the line number. The syntax errors
generated by the complier shows that the syntax errors are in Line 15. This is due to
the fact that the pointer list has no first and no last elements and so the functions
begin and end cannot be called on list.
Next, consider the following function:
void testFunc(int *p; int list[])
{
}
The function testFunc has two formal parameters: p is a pointer variable of type
int, and list is an array of type int. Now p is a pointer of type int, so it can contain
the address of an int variable and the base address of an int array. Suppose that in a
call to function testFunc, p contains the base address of an array. However, during 1
compilation p does not have the first and the last elements, so in the definition of the
function testFunc, a range-based for loop cannot be used on p. Next, consider the 2
formal parameter list. Even though list is declared as an array, it is still a pointer
of type int and can only contain the base address of any array of type int. However,
during compilation list does not have the first and the last elements, so in the defi-
nition of the function testFunc, a range-based for loop cannot be used on list.

Functions and Pointers


A pointer variable can be passed as a parameter to a function either by value or by
reference. To declare a pointer as a value parameter in a function heading, you use
Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
842 | Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

the same mechanism as you use to declare a variable. To make a formal parameter be
a reference parameter, you use & when you declare the formal parameter in the func-
tion heading. Therefore, to declare a formal parameter as a reference pointer param-
eter, between the data type name and the identifier name, you must include * to make
the identifier a pointer and & to make it a reference parameter. The obvious question
is: In what order should & and * appear between the data type name and the identifier
to declare a pointer as a reference parameter? In C11, to make a pointer a reference
parameter in a function heading, * appears before the & between the data type name
and the identifier. The following example illustrates this concept:
void pointerParameters(int* &p, double *q)
{
.
.
.
}
In the function pointerParameters, both p and q are pointers. The parameter p is a
reference parameter; the parameter q is a value parameter. Furthermore, the function
pointerParameters can change the value of *q, but not the value of q. However, the
function pointerParameters can change the value of both p and *p.

Pointers and Function Return Values


In C11, the return type of a function can be a pointer. For example, the return type
of the function
int* testExp(...)
{
.
.
.
}
is a pointer of type int.

Dynamic Two-Dimensional Arrays


The beginning of this section discussed how to create dynamic one-dimensional
arrays. You can also create dynamic multidimensional arrays. In this section, we
discuss how to create dynamic two-dimensional arrays. Dynamic multidimensional
arrays are created similarly.
There are various ways you can create dynamic two-dimensional arrays. One way is
as follows. Consider the statement:
int *board[4];

Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
Dynamic Arrays | 843

This statement declares board to be an array of four pointers wherein each pointer
is of type int. Because board[0], board[1], board[2], and board[3] are point-
ers, you can now use these pointers to create the rows of board. Suppose that each
row of board has six columns. Then, the following for loop creates the rows of
board.
for (int row = 0; row < 4; row++)
board[row] = new int[6];
Note that the expression new int[6] creates an array of six components of type int
and returns the base address of the array. The assignment statement then stores the
returned address into board[row]. It follows that after the execution of the previous
for loop, board is a two-dimensional array of four rows and six columns.
In the previous for loop, if you replace the number 6 with the number 10, then the
loop will create a two-dimensional array of four rows and 10 columns. In other words,
the number of columns of board can be specified during execution. However, the
way board is declared, the number of rows is fixed. So in reality, board is not a true
dynamic two-dimensional array.
Next, consider the following statement:
int **board;

This statement declares board to be a pointer to a pointer. In other words, board


and *board are pointers. Now board can store the address of a pointer or an array of
pointers of type int, and *board can store the address of an int memory space or an
array of int values.
Suppose that you want board to be an array of 10 rows and 15 columns. To accom-
plish this, first we create an array of 10 pointers of type int and assign the address of
that array to board. The following statement accomplishes this:
board = new int* [10]; //create an array of 10 int pointers

Because the elements of board are int pointers, each of them can point to an array
of int values.
Next, we create the columns of board. The following for loop accomplishes this:
for (int row = 0; row < 10; row++)
1
board[row] = new int[15]; 2
To access the components of board, you can use the array subscripting notation dis-
cussed in Chapter 8.
Note that the number of rows and the number of columns of board can be specified
during program execution. The following program further explains how to create
two-dimensional arrays.

Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
844 | Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

E X AMPL E 12-7

#include <iostream> //Line 1


#include <iomanip> //Line 2

using namespace std; //Line 3

void fill(int **p, int rowSize, int columnSize); //Line 4


void print(int **p, int rowSize, int columnSize); //Line 5

int main() //Line 6


{ //Line 7
int **board; //Line 8

int rows; //Line 9


int columns; //Line 10

cout << "Line 11: Enter the number of rows "


<<"and columns: "; //Line 11
cin >> rows >> columns; //Line 12
cout << endl; //Line 13

//Create the rows of board


board = new int* [rows]; //Line 14

//Create the columns of board


for (int row = 0; row < rows; row++) //Line 15
board[row] = new int[columns]; //Line 16

//Insert elements into board


fill(board, rows, columns); //Line 17

cout << "Line 18: Board:" << endl; //Line 18

//Output the elements of board


print(board, rows, columns); //Line 19

return 0; //Line 20
} //Line 21

void fill(int **p, int rowSize, int columnSize)


{
for (int row = 0; row < rowSize; row++)
{
cout << "Enter " << columnSize << " number(s)"
<< " for row number " << row << ": ";
for (int col = 0; col < columnSize; col++)
cin >> p[row][col];
cout << endl;
}
}
Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
Shallow versus Deep Copy and Pointers | 845

void print(int **p, int rowSize, int columnSize)


{
for (int row = 0; row < rowSize; row++)
{
for (int col = 0; col < columnSize; col++)
cout << setw(5) << p[row][col];
cout << endl;
}
}

Sample Run: In this sample run, the user input is shaded.


Line 11: Enter the number of rows and columns: 3 4

Enter 4 number(s) for row number 0: 1 2 3 4

Enter 4 number(s) for row number 1: 5 6 7 8

Enter 4 number(s) for row number 2: 9 10 11 12

Line 18: Board:


1 2 3 4
5 6 7 8
9 10 11 12
The preceding program contains the functions fill and print. The function fill
prompts the user to enter the elements of a two-dimensional array of type int. The
function print outputs the elements of a two-dimensional array of type int.
For the most part, the preceding output should be clear. Let us look at the statements in
the function main. The statement in Line 8 declares board to be a pointer to a pointer
of type int. The statements in Lines 9 and 10 declare int variables rows and columns.
The statement in Line 11 prompts the user to input the number of rows and number of
columns. The statement in Line 12 stores the number of rows in the variable rows and
the number of columns in the variable columns. The statement in Line 14 creates the
rows of board, and the for loop in Lines 15 and 16 creates the columns of board. The
statement in Line 17 uses the function fill to fill the array board, and the statement
in Line 19 uses the function print to output the elements of board.
1
Shallow versus Deep Copy and Pointers 2
In an earlier section, we discussed pointer arithmetic and explained that if we are
not careful, one pointer might access the data of another (completely unrelated)
pointer. This event might result in unsuspected or erroneous results. Here, we discuss
another peculiarity of pointers. To facilitate the discussion, we will use diagrams to
show pointers and their related memory.
Consider the following statements:
int *first;
int *second;

Copyrightfirst = new
2018 Cengage int[10];
Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
846 I Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

The first two statements declare first and second pointer variables of type int.
The third statement creates an array of 10 components, and the base address of the
array is stored into first (see Figure 12-8 ). (Note that first together with the arrow
indicates that first points to the allocated memory.)

'''"' 1)-- •
1 •••••••••

FIGURE 12-8 Pointer f i rst and the array 10 which it ~ints

Suppose that some meaningful data is stored in the array pointed to by first. To be
specifi c, suppose that this array is as shown in Figure 12 -9.

FIGURE 12-9 Pointer f i rst and its array

Next, consider the following statement:


second = first; // Line A

This statement copies the memory address held by first into second. After this state-
ment executes, both first and second point to the same array, as shown in Figure 12-10.

FIGURE 12-10 f i rst and second after the statement second .. first; executes

Let us next execute the following statement:


delete [] second;

After this statement executes, the array pointed to by second is deleted. This action
results in Figure 12- 11.

rirst

s.cond

FIGURE 12-11 f i rst and second after the statement delete [] second; executes
Copyright 2018 Ceogagel"",m,ng. All Rights Rese<Ved. May oot be cOIIied, scanned, orduplicated, in wilDIe or in pan. WCN 02_200_203
Classes and Pointers: Some Peculiarities I 847

Because first and second point to the same array, after the statement
delete [] second;

executes, first becomes invalid; that is, first (as well as second) are now dangling
pointers. Therefore, if the program later tries to access the memory pointed to by
first, either the program will access the wrong memory or it will terminate in an
error. This case is an example of a shallow copy. More formally, in a shallow copy,
two or more pointers of the same type point to the same memory; that is, they point
to the same data.
On the other hand, suppose that instead of the earlier statement, second = first;
(in Line A), we have the following statements:
second = new int [lO];

for ( int j = 0; j < 10; j++)


second[j] = first[j];

The first statement creates an array oEl 0 components of type in t , and the base address
of the array is stored in second. The second statement copies the array pointed to by
first into the array pointed to by second (see Figure 12-12).

first I"1-Dlmmmmmmmmm
second I"1-Dlmmmmmmmmm
FIGURE 12-12 firs t and second both pointing to their own data

Both first and second now point to their own data. If second deletes its memory,
there is no effect on first. This case is an example of a deep copy. More formally, in
a deep copy, two or more pointers of the same type each point to their own copy of
the data.
From the preceding discussion, it follows that you must know when to use a shallow
copy and when to use a deep copy.

Classes and Pointers: Some Peculiarities


In a previous section, we discussed how to use the arrow notation to access class
members via the pointer if a pointer variable is of a class type. Because a class can
have pointer member variables, this section discusses some peculiarities of such
classes. To facilitate the discussion, we will use the following class:
class ptrMemberVarType
{
Copyright 2018 Ceogagel"",m,ng. All Rights Rese<Ved. May oot be COIIied, Kanne<!, orduplicated, in wilDIe or in pan. WCN 02_200_203
876 | Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

class with the addresses of the private member variables. Sometimes, however, it is
necessary to return the address of a private member variable, as we will see in the
next chapter. How can we prevent the program from directly manipulating the pri-
vate member variables? To fix this problem, we use the word const before the return
type of the function. This way, we can still return the addresses of the private member
variables, but at the same time prevent the programmer from directly manipulating the
private member variables. Let us rewrite the class testAddress using this feature.
class testAddress
{
public:
void setX(int);
void printX() const;
const int& addressOfX(); //this function returns the
//address of the private data
//member
private:
int x;
};
The definition of the function addressOfX in the implementation file is:
const int& testAddress::addressOfX()
{
return x;
}

The same program will now generate a compile-time error.

Q U I C K REVIEW
1. Pointer variables contain the addresses of other variables as their values.
2. In C11, no name is associated with the pointer data type.
3. A pointer variable is declared using an asterisk, *, between the data type
and the variable. For example, the statements
int *p;
char *ch;
declare p and ch to be pointer variables. The value of p points to a mem-
ory space of type int, and the value of ch points to a memory space of
type char. Usually, p is called a pointer variable of type int, and ch is
called a pointer variable of type char.
4. In C11, & is called the address of operator.
5. The address of operator returns the address of its operand. For example, if
p is a pointer variable of type int and num is an int variable, the statement
p = &num;

sets the value of p to the address of num.


Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
Address of Operator and Classes | 877

6. When used as a unary operator, * is called the dereferencing operator.


7. The memory location indicated by the value of a pointer variable is
accessed by using the dereferencing operator, *. For example, if p is a
pointer variable of type int, the statement
*p = 25;

sets the value of the memory location indicated by the value of p to 25.
8. You can use the member access operator arrow, ->, to access the com-
ponent of an object pointed to by a pointer.
9. Pointer variables are initialized using either 0 (the integer zero), NULL, or
the address of a variable of the same type. In C11 11 and later standards,
you can initialize a pointer variable using (reserved word) nullptr.
10. The only number that can be directly assigned to a pointer variable is 0.
11. The only arithmetic operations allowed on pointer variables are incre-
ment (++), decrement (--), addition of an integer to a pointer variable,
subtraction of an integer from a pointer variable, and subtraction of a
pointer from another pointer.
12. Pointer arithmetic is different than ordinary arithmetic. When an inte-
ger is added to a pointer, the value added to the value of the pointer
variable is the integer times the size of the object to which the pointer
is pointing. Similarly, when an integer is subtracted from a pointer, the
value subtracted from the value of the pointer variable is the integer
times the size of the object to which the pointer is pointing.
13. Pointer variables can be compared using relational operators. (It makes
sense to compare pointers of the same type.)
14. The value of one pointer variable can be assigned to another pointer
variable of the same type.
15. A variable created during program execution is called a dynamic
variable.
16. The operator new is used to create a dynamic variable.
17. The operator delete is used to deallocate the memory occupied by a
1
dynamic variable. 2
18. In C11, both new and delete are reserved words.
19. The operator new has two forms: one to create a single dynamic variable
and another to create an array of dynamic variables.
20. If p is a pointer of type int, the statement
p = new int;

allocates storage of type int somewhere in memory and stores the


address of the allocated storage in p.
Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
878 | Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

21. The operator delete has two forms: one to deallocate the memory
occupied by a single dynamic variable and another to deallocate the
memory occupied by an array of dynamic variables
22. If p is a pointer of type int, the statement:
delete p;

deallocates the memory pointed to by p.


23. The array name is a constant pointer. It always points to the same mem-
ory location, which is the location of the first array component.
24. To create a dynamic array, the form of the new operator that creates an
array of dynamic variables is used. For example, if p is a pointer of type
int, the statement
p = new int[10];

creates an array of 10 components of type int. The base address of the


array is stored in p. We call p a dynamic array.
25. Array notation can be used to access the components of a dynamic array. For
example, suppose p is a dynamic array of 10 components. Then, p[0] refers
to the first array component, p[1] refers to the second array component,
and so on. In particular, p[i] refers to the (i +1)th component of the array.
26. An array created during program execution is called a dynamic array.
27. If p is a dynamic array, then the statement
delete [] p;

deallocates the memory occupied by p—that is, the components of p.


28. C11 allows a program to create dynamic multidimensional arrays.
29. In the statement int **board;, the variable board is a pointer to a pointer.
30. In a shallow copy, two or more pointers of the same type point to the
same memory space; that is, they point to the same data.
31. In a deep copy, two or more pointers of the same type have their own
copies of the data.
32. If a class has a destructor, the destructor is automatically executed
whenever a class object goes out of scope.
33. If a class has pointer member variables, the built-in assignment opera-
tors provide a shallow copy of the data.
34. A copy constructor executes when an object is declared and initialized
by using the value of another object and when an object is passed by
value as a parameter.
35. C11 allows a user to pass an object of a derived class to a formal param-
eter of the base class type.
Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
Exercises | 879

36. The binding of virtual functions occurs at execution time, not at com-
pile time, and is called dynamic, or run-time, binding.
37. In C11, virtual functions are declared using the reserved word virtual.
38. A class is called an abstract class if it contains one or more pure virtual
functions.
39. Because an abstract class is not a complete class—as it (or its implemen-
tation file) does not contain the definitions of certain functions—you
cannot create objects of that class.
40. In addition to the pure virtual functions, an abstract class can contain
instance variables, constructors, and functions that are not pure virtual.
However, the abstract class must provide the definitions of constructors
and functions that are not pure virtual.
41. The address of operator can be used to return the address of a private
member variable of a class.

E XE R CISES
The number in parentheses at the end of an exercise refers to the learning objective
listed at the beginning of the chapter.
1. Mark the following statements as true or false.
a. In C11, pointer is a reserved word. (1)
b. In C11, pointer variables are declared using the word pointer. (2)
c. The address of operator returns the address and value of its operand. (3)
d. If p is a pointer variable, then *p refers to the memory location to
which p points. (3)
e. In C11, the dereferencing operator has a higher precedence than
the dot operator. (4)
f. Variables that are created during program execution are called
dynamic variables. (5)
g. Dynamic variables are destroyed using the operator new. (5, 6)
1
h. The statement delete p; deallocates the variable pointer p. (6) 2
i. The statement delete p; deallocates the dynamic variable that is
pointed to by p. (6)
j. If p is a pointer variable, then the statement p = p * 2; is valid in
C11. (7)
k. Given the declaration:
int list[10];
int *p;
Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
880 | Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

the statement
p = list;
is valid in C11. (8)
l. Given the declaration:
int *p;
the statement
p = new int[50];
dynamically allocates an array of 50 components of type int, and p
contains the base address of the array. (8)
m. If a pointer p points to a dynamic array, the elements of p can be
processed using a range-based for loop. (9)
n. In C11, the return type of a function can be a pointer. (10)
o. In a shallow copy, two or more pointers of the same type point to the
same memory. (11)
p. The binding of virtual functions occurs at compile time. (13)
2. Given the declaration:
int num1, num2;
int *p1;
int *p2;
double *p3;
Mark the following statements as valid or invalid. If a statement is
invalid, explain why. (2, 3)
a. p1 = &num1;
b. num2 = num1 - *p2;
c. p3 = p2;
d. *p3 = num1;
e. *p3 = *p1;
f. num1 5 p2;
g. p1 = &p2;
h. p3 = &num1;
i. num1 = *p3;
j. num2 = &p1;
3. a. How is * used to create pointers? Give an example to justify your
answer. (2)
b. How is * used to dereference pointers? Give an example to justify
your answer. (2)
4. Consider the following statement:
int* p, q;
This statement could lead to what type of misinterpretation? (2)
Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
Exercises | 881

5. Suppose that you have the declaration int *numPtr;. What is the differ-
ence between the expressions *numPtr and &numPtr? (3)

6. What is the output of the following C11 code? (2, 3)


int int1 = 26;
int int2 = 45;
int *int1Ptr = &int1;
int *int2Ptr = &int2;

*int1Ptr = 89;
*int2Ptr = 62;
int1Ptr = int2Ptr;
*int1Ptr = 80;
int1 = 57;

cout << int1 << " " << int2 << endl;
cout << *int1Ptr << " " << *int2Ptr << endl;
7. Given the following statements:
int num;
int *numPtr;
write C11 statements that use the variable numPtr to increment the
value of the variable num. (2, 3)

8. What is the output of the following C11 code? (2, 3)


string str1 = "sunny";
string str2 = "cloudy";
string *s1;

cout << str1 << " " << str2 << endl;

s1 = &str1;
str1 = str2;
str2 = *s1;

cout << str1 << " " << str2 << endl;
9. What is the output of the following C11 code? (2, 3)
1
double dec1 = 2.5; 2
double dec2 = 3.8;
double *p, *q;

p = &dec1;
*p = dec2 - dec1;

q = p;
*q = 10.0;

Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
882 | Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

*p = 2 * dec1 + (*q);
q = &dec2;
dec1 = *p + *q;

cout << dec1 << " " << dec2 << endl;
cout << *p << " " << *q << endl;
10. The following code should output the radius of the base, height, volume,
and surface area of a cylinder. However, it fails to do so. Correct this
code to accomplish the desired results. After correcting the code, what
is the output? Do not alter the values assigned to the radius of the base
and the height of the cylinder. (2, 3, 6)
double *baseRadius;
double *height;

cout << fixed << showpoint << setprecision(2);

baseRadius = new double;


*baseRadius = 1.5;

height = new double;

*height = 2 * (*baseRadius);

baseRadius = new double;


*baseRadius = 4.0;

cout << "Radius of the base: " << baseRadius << endl;
cout << "Height: " << height << endl;
cout << "Volume: " << 3.14 * (baseRadius) * (baseRadius)
<< endl;
cout << "Surface area: "
<< 2 * 3.14 * (baseRadius) * (height) << endl;
11. The following code is intended to find the area and perimeter of a rect-
angle. However, it fails to do so. Provide the correct code to accomplish the
desired result. Also, do not modify the numeric values assigned to the vari-
ables in the code. After correcting the code, what is the output? (2, 3, 6)
double *length;
double *width;

cout << fixed << showpoint << setprecision(2);

length = new double;


length = 6.5;

&width = 3.0;

cout << "Area: " << (*length) * (&width) << ", ";
cout << "Perimeter: " << 2 * (*length 1 width) << endl;

Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
Exercises | 883

12. What is the output of the following C11 code? (2, 3, 6)


int *myPtr = new int;
int *yourPtr = new int;

*myPtr = 10;
*yourPtr = 2 * *myPtr + 3;
cout << *myPtr << " " << (*yourPtr - *myPtr + 5) << endl;

myPtr = yourPtr;
yourPtr = new int;
*yourPtr = 8;
cout << *myPtr << " " << *yourPtr << endl;

*myPtr = 17;
*yourPtr = 4;

cout << *myPtr << " " << *yourPtr << endl;
13. What is the output of the following C11 code? (2, 3, 6)
double *trip1Cost = new double;
double *trip2Cost = new double;
double *trip3Cost = new double;
double *max;

*trip1Cost = 100.00;
*trip2Cost = 350.00;
trip3Cost = trip2Cost;
trip2Cost = trip1Cost;
trip1Cost = new double;
*trip1Cost = 175;
*trip3Cost = 275;

cout << fixed << showpoint << setprecision(2);

cout << "Trip total cost: $"


<< (*trip1Cost + *trip2Cost + *trip3Cost) << endl;

max = trip1Cost;
if (*max < *trip2Cost) 1
max = trip2Cost;
if (*max < *trip3Cost) 2
max = trip3Cost;

cout << "Highest trip cost: $" << *max << endl;
14. The following code has syntax errors. Provide the correct code and the
output. (2, 3, 6)
int *speed = new int; //Line 1
double *travelTime; //Line 2
double *distance; //Line 3

Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
884 | Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

&speed = 65; //Line 4


*travelTime = 8.5; //Line 5

distance = new double; //Line 6

distance = (*speed) * (*travelTime); //Line 7

cout << *distance << endl; //Line 8


15. What is wrong with the following code? (2, 3, 6)
double *firstPtr = new double; //Line 1
double *nextPtr = new double; //Line 2

*firstPtr = 62; //Line 3


nextPtr = firstPtr; //Line 4
delete firstPtr; //Line 5
delete nextPtr; //Line 6
firstPtr = new double; //Line 7
*firstPtr = 28; //Line 8

cout << *firstPtr << " " << *nextPtr << endl; //Line 9
16. What is the output of the following code? (2, 3, 6)
int *myPtr = new int;
int *yourPtr;

*myPtr = 15;
yourPtr = new int;
delete myPtr;
myPtr = yourPtr;
*yourPtr = 28;
myPtr = new int;
*myPtr = 49;
*yourPtr = 34;
delete yourPtr;
yourPtr = myPtr;
myPtr = new int;
*myPtr = 54;

cout << *myPtr << " " << *yourPtr << endl;
17. What is stored in numList after the following code executes? (8)
int numList[6] = {25, 37, 62, 78, 92, 13};
int *listPtr = numList;
int *temp = listPtr + 2;
int num;

*listPtr = *(listPtr + 1) - *listPtr;


listPtr++;
num = *temp;
temp++;

Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
Exercises | 885

listPtr++;
*listPtr = *temp;
*temp = num;
listPtr = listPtr + 2;
*listPtr = *(listPtr - 1);
18. What is the output of the following code? (8)
int *intArrayPtr;
int *temp;
intArrayPtr = new int[5];
*intArrayPtr = 7;
temp = intArrayPtr;

for (int i = 1; i < 5; i++)


{
intArrayPtr++;
*intArrayPtr = *(intArrayPtr - 1) 1 2 * i;
}

intArrayPtr = temp;

for (int i = 0; i < 5; i++)


{
cout << *intArrayPtr << " ";
intArrayPtr++;
}

cout << endl;


19. Suppose that numPtr is a pointer of type int and gpaPtr is a pointer of
type double. Further suppose that numPtr = 1050 and gpaPtr = 2000.
Also suppose that the size of the memory allocated for an int value is
4 bytes and the size of the memory allocated for a double value is 8
bytes. What are the values of numPtr and gpaPtr after the statements
numPtr = numPtr + 2; and gpaPtr = gpaPtr + 3; execute? (7)

20. What does the operator new do? (6)

21. What does the operator delete do? (6) 1


2
22. Assume that the input is: 10 70 20 40 60. What is the output of the
following code? (8)
int *intList;

intList = new int[5];

for (int i = 0; i < 5; i++)


cin >> intList[i];

for (int i = 4; i > 0; i--)


Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
886 | Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

intList[i] = intList[i] + intList[i - 1];

int sum = 0;
for (int i = 0; i < 5; i++)
{
cout << intList[i] << " ";
sum = sum 1 intList[i];
}

cout << endl << "Sum = " << sum << endl;
23. Consider the following statement. (8)
double *sales;

a. Write the C11 statement that dynamically creates an array of 50


components of type double and assigns the base address of the
array to sales.
b. Write a C11 code that inputs data into the array sales from the
standard input device.
c. Write a C11 code that finds the index of the largest entry in the
array sales.
d. Write a C11 statement that deallocates the memory space of array
to which sales points.

24. Consider the following C11 code. (6, 8)


string seasons[4] = {"Winter", "Spring", "Summer", "Fall"};
string *strPtr;
strPtr = new string[5];
for (int i = 0; i < 4; i++)
strPtr[i] = seasons[i];
a. Write a C11 code that outputs the contents of the array to which
strPtr points.
b. Write the C11 statement that deallocates the memory space occu-
pied by the array to which strPtr points.

25. Explain why you cannot use a range-based for loop on dynamic arrays. (9)

26. What is wrong with the following code? (9)


double *p; //Line 1

p = new double[5]; //Line 2

for (int i = 0; i < 5; i++) //Line 3


p[i] = pow(i, 2.0); //Line 4

Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
Exercises | 887

for (auto x: p) //Line 5


cout << x << " "; //Line 6

cout << endl; //Line 7


27. Explain the difference between a shallow copy and a deep copy of data. (11)
28. In the C11 code given in (a) and (b), find any syntax or logical errors. (8, 11)
a. int *myPtr = new int; //Line 1
int *yourPtr; //Line 2

*myPtr = 5; //Line 3
yourPtr = myPtr; //Line 4
cout << *yourPtr << endl; //Line 5
delete yourPtr; //Line 6
cout << *myPtr << endl; //Line 7
b. int *myListPtr = new int[10]; //Line 1
int *yourListPtr; //Line 2

for (int i = 0; i < 10; i++) //Line 3


myListPtr[i] = i * (i - 1); //Line 4

yourListPtr = myListPtr; //Line 5

delete [] yourListPtr; //Line 6

for (int i = 0; i < 10; i++) //Line 7


cout << myListPtr[1] << " "; //Line 8

cout << endl; //Line 9


29. In the following code both myList and yourList are dynamic arrays of the
same size. The code initializes the array myList to certain values. The value
in each element of yourList should be twice the value in the corresponding
element in myList. However, the output of this code would show that is not
the case. Provide the correct code to accomplish the desired results. (8, 11)
int *myList;
int *yourList;
1
myList = new int[5];
myList[0] = 8; 2
for (int i = 1; i < 5; i++)
myList[i] = i * myList[i - 1];

yourList = myList;
for (int i = 0; i < 5; i++)
yourList[i] = 2 * myList[i];
30. a. Write a statement that declares votes to be pointer of type int. (1)
b. Write a C11 code that dynamically creates a two-dimensional array
of 50 rows and 10 columns and votes contains the base address of
Copyright 2018 Cengagethat array.
Learning. (8) Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203
All Rights
888 | Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes

c. Write a C11 code that outputs the data stored into the array
votes one row per line. (8)
d. Write a C11 code that deallocates the memory space occupied by
the two-dimensional array to which votes points. (8)

31. What is the purpose of a copy constructor? (12)

32. Name two situations when a copy constructor executes. (12)

33. Name three things that you should do for classes with pointer member
­variables. (12)

34. Suppose that you have the following classes, small and notSmall:
class small
{
public:
void print() const;
int add() { return x + y; }
small() {}
small(int a, int b) { x = a; y = b; }

private:
int x = 0;
int y = 0;
};

void small::print() const


{
cout << "small: -- "<< endl
<< "x: " << x << ", y = " << y << endl;
}

class notSmall: public small


{
public:
void print() const;
int add();
notSmall() {}
notSmall(int a, int b, int c)
: small(a, b) { z = c; }

private:
int z;
};

void notSmall::print() const


{
small::print();
cout << "noSmall--- z: " << z << endl;
}
Copyright 2018 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. WCN 02-200-203

You might also like