If the array elements are of a class type, the class must have a default constructor, since you cannot supply an initialization list when calling new[].. To do so, a newer bigger array i
Trang 1The operators newanddeletewere designed to create and destroy instances of a class dynamically In this case, in addition to allocating memory, a suitable constructor must
be called Before releasing memory, the destructor must be called to perform cleaning up tasks However, the operators newanddeleteensure that this happens
䊐 Calling new with a Default Constructor
A call to newfor a class is not much different from a call for a fundamental type Unless explicitly initialized, the default constructor is called for each new object, but you must make sure that a default constructor exists!
Example: Euro* pEuro = new Euro;
This statement allocates memory for an object of the Euroclass If enough memory is available, the default constructor for Eurois executed and the address of a new object returned
䊐 Explicit Initialization
To initialize an object explicitly, you can state its initial values in parentheses when you callnew
Syntax: Type *ptr = new Type(initializing_list);
The values in the initialization list are passed as arguments to the constructor If the compiler is unable to locate a suitable constructor, an error message occurs
Example: Euro *pE = new Euro( -123,77);
This statement assigns the address of a new Euro class object to the pointer pE The object is initialized using the supplied values The expression *pEthus represents the entire object
Example: *pE += 200; // To add 200 euros
Thepublicmembers are referred to via the member access operator ->
Example: cout << pE->getCents() << endl; // 33
䊐 Releasing Memory
When an object that was created dynamically is destroyed, the deleteoperator makes sure that the object is cleaned up The destructor is first called, and only then is the memory space released
As previously discussed in the section on fundamental types, when you call delete
you must ensure that the pointer is addressing a dynamic object or that you are dealing with a NULL pointer
Trang 2460 C H A P T E R 2 1 D Y N A M I C M E M O R Y A L L O C A T I O N
// DynArr.cpp // Operators new[] and delete[] for dynamic arrays //
-#include <iostream>
#include <iomanip>
using namespace std;
int main() {
cout << "Using a dynamic array.\n" << endl;
int size = 0, cnt = 0, step = 10, i;
float x, *pArr = NULL; cout << "Enter some numbers!\n"
"End with q or another character " << endl; while( cin >> x)
{ if( cnt >= size) // Array too small? { // => enlarge it
float *p = new float[size+step];
// Copy the numbers: for( i = 0; i < size; ++i)
p[i] = pArr[i];
delete [] pArr; // Release old array: pArr = p; size += step;
} pArr[cnt++] = x;
} // Work with the numbers:
if( cnt == 0) cout << "No invalid input!" << endl;
else { float sum = 0.0;
cout << "Your input: " << endl;
for( i = 0; i < cnt; i++) // To output and { // add
cout << setw(10) << pArr[i];
sum += pArr[i];
} cout << "\nThe average: " << sum/cnt << endl; }
delete [] pArr; // To free the storage return 0;
}
■ DYNAMIC STORAGE ALLOCATION FOR ARRAYS
Sample program
Trang 3Imagine you are compiling a program that will store an unknown quantity of elements in
an array Your best option is to let the program create the array dynamically An array of
this type is known as a dynamic array.
Thenew[ ]operator is available for creating dynamic arrays When you call the opera-tor, you must supply the type and quantity of the array elements
Syntax: vekPtr = new Type[cnt];
The pointer vekPtr will then reference the first of a total of cnt array elements
vekPtrhas to be a pointer to Typefor this reason Of course, Typecan also be a class
Example: Account *pk = new Account[256];
This statement allocates memory for 256 Accounttype objects and uses the default con-structor to initialize them Those objects are
pk[0], pk[1], , pk[255],
or in pointer notation:
*pk, *(pk + 1), , *(pk + 255)
If the array elements are of a class type, the class must have a default constructor, since you
cannot supply an initialization list when calling new[] Starting values for the array ele-ments cannot be assigned until later
It is always a good idea to release the memory space occupied by a dynamic array, if the array is no longer needed To do so, simply call the delete[]operator The braces []
tell the compiler to release the whole array, and not just a single array element
Example: delete[] pk;
The operand for delete[]—the pointer pkin this case—must reference the place in
memory that was allocated by a call to new[]! The destructor belonging to the current class is called for each array element This shows the big difference to delete, which would merely call the destructor for *pk, i.e for the first array element
The program on the opposite page stores numbers in a dynamic array The size of the array is adjusted as required To do so, a newer bigger array is created, the data is copied
to the new array, and the memory occupied by the old array is released
Trang 4462 C H A P T E R 2 1 D Y N A M I C M E M O R Y A L L O C A T I O N
1st element 2nd element 3rd element
first
New last element
last
1st element 2nd element 3rd element
Info
Info
■ APPLICATION: LINKED LISTS
A simple linked list
Appending a list element
Deleting a list element
first
Removed element
New first element
New second element
Trang 5䊐 Dynamic Data Structures
Now, let’s implement a linked list as a sample application A linked list is a dynamic data structure that allows easy insertion and deletion of data A data structure defines how data
can be organized in units, stored, and manipulated—as arrays, lists, or trees, for example The type of data structure you choose has a far-reaching effect on the amount of memory you need, the speed of access to the data involved, and the complexity (or sim-plicity) of the algorithms (data operations) you need
In contract to a static data structure, whose size is known before a program is launched, a dynamic data structure can change size while a program is running One
example of this is an array whose size can be changed during runtime
䊐 Defining a Linked List
Another example is a linked list that is stored in main memory and has the following characteristics:
■ each list element contains a data store for the live data and a pointer to the next element in the list
■ each list element—except the first and last elements—has exactly one predeces-sor and one succespredeces-sor The first element in the list has no predecespredeces-sor and the last element no successor
Some elementary operations are defined for linked lists, such as inserting and deleting list
elements, or searching for and retrieving the information stored in a list element
䊐 Advantages
The storage used for the list elements need not be contiguous The main advantage of linked lists is:
■ memory for the list elements is only allocated when needed
■ you only need to move a pointer when inserting or deleting list elements
When an array element is inserted or deleted, the other array elements have to be moved
to make room or fill up the “gap” in the array If there is no room left, you need to allo-cate memory for a new array and copy the data to it before inserting a new element
Trang 6464 C H A P T E R 2 1 D Y N A M I C M E M O R Y A L L O C A T I O N
// List.h // Defines the classes ListEl and List
//
-#ifndef _LISTE_H_
#define _LISTE_H_
#include "Date.h" // Class Date from Chapter 14
#include <iostream>
#include <iomanip>
using namespace std;
class ListEl // A list element
{ private:
Date date; // Date double amount; // Amount of money
ListEl* next; // Pointer to successor
public:
ListEl( Date d = Date(1,1,1), double b = 0.0,
ListEl* p = NULL) : date(d), amount(b), next(p) {}
// Access methods:
// getDate(), setDate(), getAmount(), setAmount()
ListEl* getNext() const { return next; }
friend class List; };
// -// Defining the class List
class List
{ private:
ListEl* first, *last;
public:
List(){ first = last = NULL; } // Constructor
// Access to the first and last elements:
ListEl* front() const { return first; }
ListEl* back() const { return last; } // Append a new element at the end of the list:
void pushBack(const Date& d, double b);
// Delete an element at the beginning of the list
void popFront();
};
#endif // _LIST_H_
■ REPRESENTING A LINKED LIST
Classes of header file List.h
Trang 7䊐 Representing List Elements
You can use a recursive data structure to represent a linked list A recursive data structure
is a data structure containing a pointer to a data structure of the same type Of course, the data structure cannot contain itself—that would be impossible—but it does contain a pointer to itself
Now let’s look at a linked list used to represent transactions in a bank account A transaction is characterized by a date, a sum of money, and the reason for the tion Thus, the list element needed to represent a transaction will contain the transac-tion data in its data store and a pointer to the next element in the list
The class shown on the opposite page, ListEl, was designed to represent list ele-ments To keep things simple, the data store contains only the date and a sum of money The public declaration includes a constructor and access methods for the live data Later, we will be overloading the <<operator in order to output the list
It is common practice to let the pointer for the last element in the list point to NULL This also provides a termination criterion—the nextpointer just needs to be queried for
NULL
䊐 Representing a List
To identify a linked list, you just point a pointer at the first element in the list You can then use the pointer to the successor of each element to address any element in the list
A pointer to the last element in the list is useful for appending new elements
The opposite page shows the class definition for the Listclass The private section comprises two pointers, which reference the first and last list elements respectively The
constructor has an easy job—it simply points both pointers to NULL, thus creating an
empty list The destructor has a more complex task: it has to release the memory occupied
by the remaining list elements
ThepushBack()method is used to append a new element to the end of the list To
do so, memory is allocated dynamically and the new element becomes the successor of what was previously the last element and the lastpointer is updated In addition, the method must deal with a special case, where the list is empty
ThepopFront()method deletes the first element in the list This involves turning the pointer to the first element around to the second element and releasing the memory occupied by the first element The special case with an empty list also applies
Trang 8466 C H A P T E R 2 1 D Y N A M I C M E M O R Y A L L O C A T I O N
■ EXERCISES
Notes on exercise 1
Effects of the splice() function
Insert Position
Result
1 st Array
2 nd Array
7 3 5 9 6 2
9 1 4 2 6 8 3 5
7 3 9 1 4 2 6 8 3 5 5 9 6 2
Trang 9Exercise 1
Write a global function called splice()that “splices” two intarrays together
by first allocating memory for a dynamic array with enough room for both int arrays, and then copying the elements from both arrays to the new array, as follows:
■ first, the elements of the first array are inserted up to a given position,
■ then the second array is inserted,
■ then the remainder of the first array is appended
Arguments: The two intarrays, their length, and the position at which
they are to be spliced
Return value: A pointer to the new array
Exercise 2
Write a global function called merge()that merges two sorted intarrays by first allocating memory for a dynamic array with enough room for both int arrays and then inserting the elements of both arrays into the new array in sequence
Arguments: The two intarrays and their length
Return value: A pointer to the new array
To test the function, modify the program used to sort arrays in Exercise 4 of Chapter 17
Exercise 3
Complete and test the implementation of a linked list found in this chapter
■ First define the access methods shown opposite.Then overload the << operator for the class ListElto allow formatted output of the data in the list elements.You can use the asString()in the date class to do so
■ Then implement the destructor for the Listclass.The destructor will release the memory used by all the remaining elements Make sure that you read the pointer to the successor of each element before destroying it!
■ Implement the methods pushBack()andpopFront() used for append-ing and deletappend-ing list elements
■ Overload the operator <<in the Listclass to output all the data stored
in the list
■ Test the Listclass by inserting and deleting several list elements and repeatedly outputting the list
Trang 10468 C H A P T E R 2 1 D Y N A M I C M E M O R Y A L L O C A T I O N
■ SOLUTIONS
Exercise 1
// -// Splice.cpp
// Implements the splice algorithm
//
-#include <iostream>
#include <iomanip>
#include <cstdlib> // For srand() and rand()
#include <ctime> // and for time()
using namespace std;
// Prototype:
int *splice( int v1[], int len1,
int v2[], int len2, int pos);
int main() {
cout << "\n * * * Testing the splice function * * *\n"
<< endl;
int i, len1 = 10, len2 = 5;
int *a1 = new int[len1],
*a2 = new int[len2];
// Initialize the random number generator // with the current time:
srand( (unsigned)time(NULL));
for( i=0; i < len1; ++i) // Initialize the arrays: a1[i] = rand(); // with positive and for( i=0; i < len2; ++i)
a2[i] = -rand(); // negative numbers
// To output the array:
cout << "1 array: " << endl;
for( i = 0; i < len1; ++i) cout << setw(12) << a1[i];
cout << endl;
cout << "2 array: " << endl;
for( i = 0; i < len2; ++i) cout << setw(12) << a2[i];
cout << endl;
cout << "\n At what position do you want to insert "
"\n the 2nd array into 1st array?"
"\n Possible positions: 0, 1, , " << len1
<< " : ";
int pos; cin >> pos;