CH 12 - C++ Programming - DSMalik - 8e - 2018-Text
CH 12 - C++ Programming - DSMalik - 8e - 2018-Text
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.
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
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;
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;
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
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.
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 .
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=
The following shows the values of the variables after the execution of each statement.
After
Statement Values of the Variables Explanation
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
I· 1400 17.50
·1
P x
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 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.)
The program in Example 12-3 further illustrates how a pointer variable works.
E X AMPL E 12-3
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
return 0; //Line 23
} //Line 24
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.)
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;
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.
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:
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
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
p~.
(a) p
___
1500
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:
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.
cout << "Line 18: After using the delete operator, "
<< "the value stored in the location\n "
<< "to which radiusPtr is pointing: "
<< *radiusPtr << endl; //Line 18
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
return 0; //Line 26
} //Line 27
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
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++;
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
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:
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]
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 ;
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
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.
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. }
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.
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;
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
return 0; //Line 20
} //Line 21
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 •••••••••
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.
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
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];
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.
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;
}
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 = #
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;
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;
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)
*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)
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;
*height = 2 * (*baseRadius);
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;
&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
*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;
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
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;
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;
intArrayPtr = temp;
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;
25. Explain why you cannot use a range-based for loop on dynamic arrays. (9)
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
*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
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)
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;
};
private:
int z;
};