This is necessary if ■ an array of pointers is to be dynamically allocated, or ■ a function expects an array of pointers as an argument.. Example: Account** ptr = new Account*[400]; The
Trang 1S O L U T I O N S 679
kde.setNr(10L); kde.setName("Peter");
hash.insert( kde );
kde.setNr(17L); kde.setName("Alexa");
hash.insert( kde );
kde.setNr(21L); kde.setName("Peter");
hash.insert( kde );
kde.setNr(15L); kde.setName("Jeany");
hash.insert( kde );
cout << "\nInsertion complete: " << endl;
hash.display();
unsigned long key;
cout << "Key? "; cin >> key;
HashEntry temp = hash.retrieve(key);
if(temp.getNr() != 0L)
temp.display();
else
cout << "Key " << key
<< " not found" << endl;
}
catch(OpenError& err)
{
cerr << "Error in opening the file:"
<< err.getName() << endl;
exit(1);
}
catch(WriteError& err)
{
cerr << "Error writing to file: "
<< err.getName() << endl;
exit(1);
}
catch(ReadError& err)
{
cerr << "Error reading from file: "
<< err.getName() << endl;
exit(1);
}
return 0;
}
Trang 2This page intentionally left blank
Trang 36 8 1
More about Pointers
This chapter describes advanced uses of pointers.These include pointers
to pointers, functions with a variable number of arguments, and pointers
to functions.
An application that defines a class used to represent dynamic
matrices is introduced.
Trang 4682 C H A P T E R 3 0 M O R E A B O U T P O I N T E R S
// accSort.cpp: Sorts an array of pointers to accounts // according to the account numbers
//
-#include "account.h"
void ptrSwap(Account**, Account** );
void accSort( Account** kptr, int n) {
Account **temp, **minp, **lastp;
lastp = kptr + n - 1; // Pointer to the last
// pointer in the array
for( ; kptr < lastp; ++kptr ) {
minp = kptr;
for( temp = kptr + 1; temp <= lastp; ++temp ) {
if( (*temp)->getNr() < (*minp)->getNr() ) minp = temp;
} ptrSwap( kptr, minp );
} }
void ptrSwap( Account **p1, Account **p2 ) {
Account *help;
help = *p1; *p1 = *p2; *p2 = help;
}
■ POINTER TO POINTERS
The function accSort()
Trang 5P O I N T E R T O P O I N T E R S 683
䊐 Motivation
Pointer variables are objects that have an address in memory, and this means you can use
pointers to address them It is thus possible to create pointers to pointers This is necessary
if
■ an array of pointers is to be dynamically allocated, or
■ a function expects an array of pointers as an argument
In both cases you need to declare a pointer variable that can access the first element in the array Since each element in the array is a pointer, this pointer variable must be a pointer to a pointer
䊐 Generating Pointer Arrays Dynamically
Now let’s look into creating a dynamic array of pointers to Accountclass objects
Example: Account** ptr = new Account*[400];
The pointer ptr is now pointing at the first pointer in the array with a total of 400
Account*type pointers The array elements can be addressed as follows:
*ptr and ptr[0] (pointer to index 0)
*(ptr + i) and ptr[i] (pointer to index i)
Access to objects managed by the array is achieved as follows:
**ptr and *ptr[0] (object addressed by pointer at index 0)
**(ptr+i) and *ptr[i] (object addressed by pointer at index i)
䊐 Pointer Arrays as Arguments
When you define a function that expects an array of pointers as an argument, you must define parameters to match
Example: void accSort( Account **kptr, int len);
You can use the kptrparameter to manipulate a pointer array whose length is stored in the second parameter, len After calling
Example: accSort( ptr, 100);
kptr points to the first pointer ptr[0] in the pointer array ptr Instead of
Account **kptryou can also use the equivalent form Account *kptr[]
The opposite page shows an implementation of the function accSort() The func-tion uses the selecfunc-tion sort algorithm (which you have already worked with) for sorting
In this case it is important not to sort the accounts itself, but to sort the pointers instead This saves time-consuming copying
Trang 6684 C H A P T E R 3 0 M O R E A B O U T P O I N T E R S
Fixed arguments
First varying argument
Varying arguments
Last varying argument
va_start(argp,max)
char *buffer
int max
•
•
•
#include <stdarg.h>
int func( char *buffer, int max, ) {
va_list argptr; // Declares argument pointer long arg3;
va_start( argptr, max); // Initialization arg3 = va_arg( argptr, long ); // Read arguments
// To use argument arg3
va_end(argptr); // Set argument pointer to NULL }
■ VARIABLE NUMBER OF ARGUMENTS
Fixed and varying arguments on the stack
Scheme of a function with varying arguments
Trang 7V A R I A B L E N U M B E R O F A R G U M E N T S 685
C++ allows you to define functions that allow a variable number of arguments One example of a function of this type is the standard C function printf(), which requires
at least one argument, a format string The printf() function uses the conversion specifiers in the format string to compute the number and type of arguments that follow
䊐 Obligatory and Optional Arguments
Functions with a variable number of arguments always expect a fixed number of
obliga-tory arguments and a variable number of optional arguments At least one obligaobliga-tory
argu-ment is required
As you would expect, you need to define an appropriate parameter for each obligatory argument when you define a function of this type The optional arguments are repre-sented by three dots in the parameter list The function shown opposite, func(), expects two or more arguments The prototype is, thus, as follows
Prototype: int func( char *buffer, int max, );
To allow functions with a variable number of arguments to be defined, C++ pushes the last argument onto the stack first After calling the sample function func(), the stack looks like the diagram opposite
The optional arguments are accessed via a pointer, the so-called argument pointer,
which is designated by argptrhere The header files cstdargorstdarg.hcontain macros, which conform to ANSI standard, to manage the pointer and assure that the source code will be portable
䊐 Access to Arguments
The following steps are required to read the optional arguments:
1 The va_list type argument pointer argptr must be declared in addition to other local variables The type va_listis defined in the header file stdarg.h
as a typeless or charpointer
2 The macro va_start() is then called to point the argument pointer argptr
to the first optional argument va_start()expects two arguments: the name of the argument pointer and the name of the last obligatory parameter
Example: va_start( argptr, max );
Trang 8686 C H A P T E R 3 0 M O R E A B O U T P O I N T E R S
// input.cpp: The function input() reads characters // from the keyboard and appends '\0'
// The input can be corrected with backspace // Arguments: 1 Pointer to the input buffer
// 2 Maximum number of characters to be read / 3 Optional arguments: Characters that // terminate the input
// This list has to end with CR = '\r'! // Returns: Character that breaks the input
//
-#include <stdarg.h>
#include <conio.h> // For getch() and putch()
int input(char *buffer, int max, )
{ int c, breakc; // Current character, character to
// break with
int nc = 0; // Number of characters read
va_list argp; // Pointer to the following arguments while(true)
{
*buffer = '\0';
if( ( c = getch()) == 0) // Read a character
c = getch() + 256; // For special keys:
// Extended code + 256 va_start(argp, max); // Initialize argp
do // Compare with break characters: if( c == (breakc = va_arg(argp,int)) )
return(breakc);
while( breakc != '\r');
va_end( argp);
if( c == '\b' && nc > 0) // Backspace?
{ nc, buffer;
putch(c); putch(' '); putch(c);
} else if( c >= 32 && c <= 255 && nc < max ) { // Place character into the buffer ++nc, *buffer++ = c; putch(c); // and output else if( nc == max) // Is end of buffer reached? putch('\a'); // Beep
} }
■ VARIABLE NUMBER OF ARGUMENTS (CONTINUED)
The function input()
Trang 9V A R I A B L E N U M B E R O F A R G U M E N T S ( C O N T I N U E D ) 687
3 When the macro va_arg() is called, the optional argument pointed to by
argptris read from the stack The arguments of va_arg()are the name of the argument pointer and the type of the optional argument:
Example: arg3 = va_arg( argptr, long);
Each call to the macro va_arg()sets the argument pointer to the next optional argument The result of va_arg() has the type stated in the call It must be identical to the type of the corresponding optional argument
There is no special terminating condition for the last optional argument A spe-cific value (such as NULL, ⫺1orCR) can be used, or the current number of argu-ments can be defined by an obligatory argument
4 After evaluating the arguments the argument pointer is set to NULL by the
va_end()macro:
Example: va_end( argptr);
Optional arguments can also be read more than once The procedure described above is repeated beginning at Step 2, that is, with the macro va_start()
䊐 Notes on the Example Opposite
The sample function input()on the opposite page uses the getch()function to read character input from the keyboard and store it in the buffer addressed by the first argu-ment The second argument defines the maximum number of characters to be read All other arguments are characters that can terminate keyboard input The last argument
must be a return character ('\r')!
Example: #define ESC 27 // ESC key
#define F1 (256 + 59) // F1 key
input( name, 20, ' ', ESC, F1, '\r');
This call to input()reads up to 20 characters and stores them in the array name Input can be terminated by pressing the space, ESC,F1, or return keys The return value is the corresponding character code Non-printable characters are ignored unless stated as optional arguments
Special keys, such as the function keys, return a value of 0 for the first call to
getch()and the extended code for the second call For function keys this code is within
the range 59–68 To distinguish extended codes from normal ASCII codes (0–255), the value 256is added to the extended code A table of extended codes is available in the Appendix
Trang 10688 C H A P T E R 3 0 M O R E A B O U T P O I N T E R S
// funcptr.cpp: Demonstrates the use of an array // of pointers to functions
//
-#include <iostream>
#include <cstdlib> // Prototype of atoi()
#include <cctype> // Macros toupper(), tolower() using namespace std;
void error_message(char *), message(char *),
message_up(char *), message_low(char *);
void (*functab[])(char *) = { error_message, message,
message_up, message_low }; char call[]="Input: 1,2, or 3";
int main() {
int n = 0;
cout << "Which of the three functions "
<< "do you want call (1,2, or 3)?\n";
cin >> n;
if( n<1 || n>3) (*functab[0])( call );
else (*functab[n])("Hello, world\n");
return 0;
} void error_message( char *s) { cerr << s << endl; } void message( char *s) { cout << s << endl; } void message_up( char *s)
{ int c;
for( ; *s != '\0';++s) c = toupper(*s),cout.put(c); }
void message_low( char *s) { int c;
for( ; *s != '\0';++s) c = tolower(*s), cout.put(c); }
■ POINTERS TO FUNCTIONS
A jump table