The final version of the Rolodex program utilizes concepts and C library functions introduced previously. Please review the following as needed:
The next version of the Rolodex database program adds an index file to speed access to the rolodex records stored in the data file. As before, we focus on demonstrating the C++ stream member functions that enable the described functionality rather than on producing product-ready code. As such, we'll rely on a binary search, implemented with library functions, to look up the keys in the index file. The final version of the Rolodex program consists of five files:
The following figures describe the main features of the Rolodex database program. The source code for the complete program is available at the bottom of the page.
Feature | Description |
---|---|
char name[NAME_SZ]; streampos pos; |
Private member fields for the name and data record position fields. |
key() |
Constructor that builds an empty key. |
key(char* n) |
Constructor that builds a key with just the name field filled - used to create a key object for use with the bsearch library function. |
key(char* n, streampos pos) |
Constructor that build a completely filled key object for mapping a name to a position the data file. |
streampos get_pos() |
A getter function that returns the position value. |
static void sort(key* keys, int count) |
A function that sorts the keys alphabetically by name. The function is made static - i.e., a class function - because it operates on an array of key objects rather than on a single, target object. |
friend int korder(const void* e1, const void* e2) |
A function that alphabetically orders two key objects. The function's signature (i.e., the argument list and return type) cannot be changed because the function is used by two C library functions, qsort and bsearch, but the function must access private members of the key class. Making the function a friend of the key class solves the conflict. |
Feature | Description |
---|---|
fstream index; fstream data; |
Stream objects to access the index and data files; both are private data members. |
rolodex(); |
Constructor that creates and opens the index and data files. |
~rolodex() { index.close(); data.close(); } |
Destructor that closes the index and data files. |
void add(char* name, char* address, char* phone); |
Adds a new card at the end of the data file: Figure 3. |
void search(char* name); |
Searches for name in the index file; if the name is found, prints the information from the data file: Figure 4. |
void list(); |
Lists all entries in the data file in alphabetical order Figure 5. |
void edit(char* name, char* address, char* phone); |
Edits or updates an existing card in the data file: Figure 6. |
private/helper functions | |
void open(fstream& stream, char* file); |
Opens the index and data files: Figure 7. |
key* find(char* name, key* keys); |
Finds name in the index file and returns a pointer to the key: Figure 8. |
int load_keys(key* keys); |
Loads all the keys from the index file and sorts them alphabetically by name: Figure 9. |
streampos write(card& c, streampos pos = -1); |
Writes a card to the data file; if pos is -1, the card is appended at the end of the file, otherwise it is written at position pos: Figure 10. |
void append(char* name, streampos pos); |
Appends a key at the end of the index file: Figure 11. |
card read(streampos pos); |
Reads and returns a card from the data file: Figure 12. |
void rolodex::add(char* name, char* address, char* phone) { card c(name, address, phone); // (a) streampos pos = write(c); // (b) append(name, pos); // (c) }
void rolodex::search(char* name) { key keys[100]; // (a) key* match = find(name, keys); // (b) if (match != nullptr) // (c) read(match->get_pos()).print(); // (d) else cout << "Search name was not found in the Rolodex\n"; }
nullptr
if a match is not found.
void rolodex::list() { key keys[100]; // (a) int count = load_keys(keys); // (b) card c; for (int i = 0; i < count; i++) // (c) read(keys[i].get_pos()).print(); // (d) /*card c; data.seekg(0); while (data.read((char *) &c, sizeof(card))) c.print(); data.clear();*/ }
void rolodex::edit(char* name, char* address, char* phone) { key keys[100]; // (a) key* match = find(name, keys); // (b) if (match != nullptr) // (c) { streampos pos = match->get_pos(); // (d) cout << "Old: "; read(pos).print(); // (e) card c(name, address, phone); // (f) cout << "New: "; c.print(); // (g) write(c, pos); // (h) } else cout << "Search name not found\n"; }
nullptr
if a match is not found.
void rolodex::open(fstream& stream, char* file) { stream.open(file, ios::binary | ios::in | ios::out); // (a) if (!stream.is_open()) // (b) { ofstream make(file); // (c) make.close(); // (d) stream.open(file, ios::binary | ios::in | ios::out); // (e) } if (!stream.good()) // (f) { cerr << "Unable to open " << file << endl; exit(1); } }
key* rolodex::find(char* name, key* keys) { int count = load_keys(keys); // (a) key sk(name); // (b) return (key *)bsearch(&sk, keys, count, sizeof(key), korder); // (c) }
int rolodex::load_keys(key* keys) { int count = 0; // (a) index.seekg(0); // (b) while (index.read((char *) &keys[count], sizeof(key))) // (c) count++; key::sort(keys, count); // (d) index.clear(); // (e) return count; // (f) }
streampos rolodex::write(card& c, streampos pos) { if (pos == (streampos) -1) // (a) data.seekp(0, ios::end); // (b) else data.seekp(pos); // (c) pos = data.tellp(); // (d) data.write((char *) &c, sizeof(card)); // (f) data.flush(); // (g) return pos; // (h) }
void rolodex::append(char* name, streampos pos) { key k(name, pos); // (a) index.seekp(0, ios::end); // (b) index.write((char *) &k, sizeof(key)); // (c) index.flush(); // (d) }
card rolodex::read(streampos pos) { card c; // (a) data.seekg(pos); // (b) data.read((char *) &c, sizeof(card)); // (c) return c; // (d) }