Address Book Program

Hi everyone,

I'm new to C++, taking my first course, and as one of the assignments we have to create a record management program.

One of the things it has to do is be able to sort the records and display them in a certain order.

I'm creating an address book program, and so far I can add the contacts, display them, save them to a file, and open the file. I'm now trying to sort the contacts by first name, alphabetically, but I'm running into problems. The main one is that the program has to use struct, and I'm trying to sort by a string in the struct, which I have never done before.

If anyone could help point me in the right direction, I'd really appreciate it. I've been fighting with this for days.

[
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>

using namespace std;

struct AddressBook {
string firstname;
string lastname;
string addr;
string phone;
};

// Function prototypes
char getMenuResponse(); // Function to allow user to navigate program.
void addContacts(vector<AddressBook>&); // Function to add contacts.
void dispContacts(const vector<AddressBook>&); // Function to display contacts.
void saveFile(const vector<AddressBook>&); // Function to save to file.
void openFile(vector<AddressBook>&); // Function to read from file.
int findTargetFirstName(vector<AddressBook>& list, string target); // Function to find a target index
void findContact(vector<AddressBook>&); // Function to find a contact.

void sortFirstNames(vector<AddressBook>& list);

int main() {

// To operate, to avoid losing previous contacts, Open File first

vector<AddressBook> list;
bool run = true;

cout << "Welcome To My Address Book Program For Assignment 2!\n" << endl;

do {
switch (getMenuResponse()) {
case 'A': addContacts(list); break;
case 'D': dispContacts(list); break;
case 'M': sortFirstNames(list); break;
case 'O': openFile(list); break;
case 'S': saveFile(list); break;
case 'F': findContact(list); break;
case 'Q': run = false; break;
default : cout << "That is NOT a valid choice" << endl;
}
} while (run);

cout << endl << "Program Terminated" << endl;

// system("PAUSE"); // Commented out so the program exits upon request
return EXIT_SUCCESS;
}

void sortFirstNames(vector<AddressBook>& list) {
string firstname;
int i, j, min;

bool sorted = false;
bool run = true;

if(list[i].firstname > 1) {
for (i = 0; i < (list[i].firstname-1); i++) {
min = i;
for (j = (i+1); j < list[i].firstname; j++) {
if(list[j] < list[min]) min = j;
}
if (i != min) swap(list[i], list[min]);
}
sorted = true;
}
}


int findTargetFirstName(vector<AddressBook>& list, string target) {
// linear search:
for (int i = 0; i < list.size(); i++)
if (list[i].firstname == target) return i; // return ndx of target
return -1; // not in the list
}

void findContact(vector<AddressBook>& list) {
if(list.size() > 0) {
string firstname;

cout << "Enter the first name to find: ";
getline(cin, firstname);
int ndx = findTargetFirstName(list, firstname);

if (ndx >= 0) {
cout << firstname << " is at index " << ndx << "." << endl;
} else cout << firstname << " is not found!" << endl;
} else cout << "That name is not found!" << endl;
}

void addContacts(vector<AddressBook>& list) {
AddressBook tmp; // Declare a temp contact that we will load before putting in the array.
char response;
string str; // Needed for cin.getline; we are going to use a char array.
bool run = true;

do {
system("cls");
cout << "Enter Contact Information" << endl;
cout << "Enter 'quit' at Name to exit." << endl << endl;

cout << "First Name: "; // Entering first name.
getline(cin, str);
tmp.firstname = str;
cout << endl;

if (str == "quit") break;

cout << "Last Name: "; // Entering last name.
getline(cin, str);
tmp.lastname = str;
cout << endl;

cout << "Address: "; // Entering Address
getline(cin, str);
tmp.addr = str;
cout << endl;

cout << "Phone Number: "; // Entering phone number.
getline(cin, str);
tmp.phone = str;
cout << endl;

// See if this record should be added to the array.
cout << "Add Contact to Address Book? (y/n) ";
cin >> response;
cin.ignore(256, '\n');
if (toupper(response) == 'Y') {
list.push_back(tmp);
cout << "Contact added!"<< endl;
}else {
cout << "Contact not added!" << endl;
}

} while (run);
system("cls");
}

void dispContacts(const vector<AddressBook>& list) {

system("cls");

// If there is nothing in the list, statement that there are no contacts.
// Otherwise, continue.
if(list.size() < 1) {
cout << "Nothing to display" << endl;
} else {
cout << "Contacts :" << endl << endl;
cout << fixed << setprecision(2);
cout << "Contact Name Address Phone No." << endl;
cout << "*******************************************" << endl;

cout << left;
for (int i = 0; i < list.size(); i++) {
cout << setw(15) << list[i].firstname << left
<< setw(15) << list[i].lastname << left
<< setw(30) << list[i].addr << left
<< setw(15) << list[i].phone << left << endl;
}

cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << endl;
cout << right << setw(3) << list.size();
cout << " Contacts"<< endl;
}

system("PAUSE");
system("cls");
}

// Save records to file.
void saveFile(const vector<AddressBook>& list) {

string fileName;
ofstream outfi;
cout<<"Enter file name (please use addressbook.txt for now): ";
// Have set file name to addressbook.txt for now.
// Might change code to allow selection of file to load.
getline(cin,fileName);
outfi.open(fileName.c_str());

// To make sure the file stream is open before doing IO.
if (!outfi.fail()) {
system("cls");
cout << "Saving Address Book to the disc ";

for(int i = 0; i < list.size(); i++) {
outfi << list[i].firstname << ';'
<< list[i].lastname << ';'
<< list[i].addr << ';'
<< list[i].phone;
// Start a new line after all but the last record.
// Simplifies reading the file as EOF is at end of last line.
if (i < list.size()-1) outfi << endl;
}

cout << endl << list.size() << " Address Book written to the disc." << endl;
outfi.close();

system("PAUSE");
system("cls");
} else { // Something went wrong with writing to the file.
cout << "ERROR: problem with file" << endl;
system("PAUSE");
system("cls");
}
}

// Open file and load array
void openFile(vector <AddressBook>& list) {

AddressBook tmp;

// If Open File is selected after contacts are added, they will be overwritten.
// Warning user that this will occur.
// If 'N' selected, Open File will not continue, and will return to GetMenuResponse.
if (list.size() > 0) {
char response;
cout << "Are you sure? If you have already added contacts, this will "
<< "overwrite what you have entered with a previously saved "
<< "addressbook.txt." << endl;
cout << "Do you wish to proceed? (Y/N) : ";
cin >> response;
cin.ignore(256, '\n');
if(toupper(response) == 'N') return;
}

ifstream infi("addressbook.txt"); // Have set file name to addressbook.txt for now.
// Might change code to allow selection of file to load.
string str;

// Make sure the file stream is open before doing IO.
if (!infi.fail()) {

system("cls");
cout << "Reading Address Book from the disc ";

list.clear(); // Overwrite any existing records

getline(infi, str, ';');
while(!infi.eof()) {
// Store the first name.
tmp.firstname = str;
// Store the last name.
getline(infi, str, ';');
tmp.lastname = str;
// Store the address.
getline(infi, str, ';');
tmp.addr = str;
// Store the phone number.
getline(infi, str);
tmp.phone = str;
// Put tmp into the vector.
list.push_back(tmp);

getline(infi, str, ';');
}
cout << endl << list.size() << " Contacts read from the disc." << endl;

system("PAUSE");
system("cls");
} else { // Something went wrong with opening the file.
cout << "ERROR: problem with file" << endl;
system("PAUSE");
system("cls");
}
}

// Get's user's input from keyboard.
char getMenuResponse() {
char response;
cout << endl << "Make your selection" << endl
<< "(A)dd contact, \n(D)isplay Contacts, \n(M)Sort By First Name, "
<< "\n(O)pen File, \n(S)ave File, "
<<"\n(F)ind Index Of Contact By First Name, \n(Q)uit" << endl
<< "> ";
cin >> response;
cin.ignore(256, '\n');
// Clean-up up to 256 chars including the delimiter specified (\n, the endl)
// OR stop when the \n is encountered after removing it.
return toupper(response);
}
closed account (SECMoG1T)
Hi you can try this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
void my_swap (AddressBook& obj_one, AddressBook& obj_two)//helping function one
  {
     AddressBook temp=obj_one;
      obj_one=obj_two;
      obj_two=temp;
   }

 int find_smallest(const vector<AddressBook>& vec, int index)//helping function two
  {
     int smallest_index=index;
     AddressBook temp=vec [index];

     for (unsigned int i=index; i <vec.size (); i++)
        {
            if(vec [i].firstname <temp.firstname)
              {
                 smallest_index=i; 
                 temp=vec[i];
              }
         }

       return smallest_index;
     }

void sortFirstNames(vector<AddressBook>& list)//selection sort algorithm{ascending}
  {	
     for (unsigned int count=0; count <list.size (); count++)
        {
           int ind_to_swap=find_smallest (list, count);
           my_swap(list[count], list [ind_to_swap]);
        }
   }
  


Though I dint test that btw it seems fyn, but I would advice you to use the std::sort () it's better.
Last edited on
Thanks very much, but I' running into errors still.
In the void_myswap, even after I changed temp to tmp, it gives me the error
73 20 [Error] conversion from 'std::vector<AddressBook>' to non-scalar type 'AddressBook' requested.
75 12 [Error] no match for 'operator=' in 'obj_two = tmp'

I tried changing it to <vector>AddressBook, but that didn't work either.

I'm trying to sort the first names and display them in alphabetical order. I did look into the sort, and while that code compiles it doesn't display anything:

struct AddrCmpFirstNames {
bool operator ()(const AddressBook& lhs, const AddressBook& rhs)
{
return lhs.firstname < rhs.firstname;
}
};

void sortFirstNames(std::vector<AddressBook>& vec) {
std::sort(vec.begin(), vec.end(), AddrCmpFirstNames());
cout << endl;
}
closed account (SECMoG1T)
Ooh sorry for that , I dint notice your class lacked some necessary operators, anyway this should get you going, add Iit to your original code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
  /**************************************************************************************/
    AddressBook& operator =(const AddressBook& bok);///add this two to your struct
    bool operator ==(const AddressBook& bok);///
 
/***************************************************************************************/
    ///anywhere outside main add this definitions

    bool AddressBook::operator ==(const AddressBook& bok)
    {
        return (firstname==bok.firstname&&lastname==bok.lastname&&addr==bok.addr&&phone==bok.phone);
    }

    AddressBook& AddressBook::operator=(const AddressBook& bok)
    {
        if(*this==bok)
            return *this;
        else
        {
            firstname=bok.firstname;
            lastname=bok.lastname;
            addr=bok.addr;
            phone=bok.phone;
        }
         return *this;
    }

// Function prototypes.
int find_smallest(const vector<AddressBook>& vec, int index);
void my_swap (AddressBook& obj_one, AddressBook& obj_two);
void sortFirstNames(vector<AddressBook>& list);/// this three prototypes should be here

 /********************************************************************************/
  ///add this definitions too outside main.

void my_swap (AddressBook& obj_one, AddressBook& obj_two)//helping function one
  {
     AddressBook temp=obj_one;
      obj_one=obj_two;
      obj_two=temp;
   }

 int find_smallest(const vector<AddressBook>& vec, int index)//helping function two
  {
     int smallest_index=index;
     AddressBook temp=vec [index];

     for (unsigned int i=index; i <vec.size (); i++)
        {
            if(vec [i].firstname <temp.firstname)
              {
                 smallest_index=i;
                 temp=vec[i];
              }
         }

       return smallest_index;
     }

void sortFirstNames(vector<AddressBook>& list)//selection sort algorithm{ascending}
  {
     for (unsigned int count=0; count <list.size (); count++)
        {
           int ind_to_swap=find_smallest (list, count);
           my_swap(list[count], list [ind_to_swap]);
        }
   }
Last edited on
When I add these to my struct, am I adding them to struct AddressBook or struct AddrCmpFirstNames?
AddressBook& operator =(const AddressBook& bok);
bool operator ==(const AddressBook& bok);

I put them in struct AddressBook, but it still won't sort. The code compiles, but nothing displays when I select the function.


//Structs:
struct AddressBook {
string firstname;
string lastname;
string addr;
string phone;
AddressBook& operator = (const AddressBook& bok);
bool operator ==(const AddressBook& bok);
};

struct AddrCmpFirstNames {
bool operator ()(const AddressBook& lhs, const AddressBook& rhs)
{
return lhs.firstname < rhs.firstname;
}
};

//Function Prototypes:
int find_smallest(const vector<AddressBook>& vec, int index);
void my_swap (AddressBook& obj_one, AddressBook& obj_two);
void sortFirstNames(vector<AddressBook>& list);

//Definitions:
bool AddressBook::operator ==(const AddressBook& bok) {
return (firstname == bok.firstname && lastname == bok.lastname && addr == bok.addr && phone == bok.phone);
}

AddressBook& AddressBook::operator=(const AddressBook& bok) {
if(*this == bok)
return *this;
else
{
firstname = bok.firstname;
lastname = bok.lastname;
addr = bok.addr;
phone = bok.phone;
}
return *this;
}


void my_swap (AddressBook& obj_one, AddressBook& obj_two)//helping function one
{
AddressBook temp = obj_one;
obj_one = obj_two;
obj_two = temp;
}

int find_smallest(const vector<AddressBook>& vec, int index)//helping function two
{
int smallest_index = index;
AddressBook temp = vec [index];

for (unsigned int i = index; i < vec.size(); i++)
{
if(vec[i].firstname < temp.firstname)
{
smallest_index = i;
temp = vec[i];
}
}
return smallest_index;
}

void sortFirstNames(vector<AddressBook>& list)//selection sort algorithm{ascending}
{
for (unsigned int count = 0; count < list.size (); count++)
{
int ind_to_swap = find_smallest (list, count);
my_swap(list[count], list [ind_to_swap]);
}
}
closed account (SECMoG1T)
1
2
struct AddressBook//yea add the two operators into this struct
// all the other functions definitions should be outside main and outside your structs 


/// the code works for me just fine, I tested it a number of times, but did you first add some records to your vector coz it can't work on an empty vector.

maybe you can post your current code and i'll try debug it.
Last edited on
I did add records; tried both adding them with the addContact function and reading them from a stored file, but when I select the sort option it displays a blank line and goes back to the main menu.

If you would be willing to debug, that would be great. I have a feeling I'm missing something very simple, but sorts have been very frustrating.

My current code is:


#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <sstream>
#include <algorithm>
#include <vector>

using namespace std;

struct AddressBook {
string firstname;
string lastname;
string addr;
string phone;
AddressBook& operator = (const AddressBook& bok);
bool operator ==(const AddressBook& bok);
};

struct AddrCmpFirstNames {
bool operator ()(const AddressBook& lhs, const AddressBook& rhs)
{
return lhs.firstname < rhs.firstname;
}
};

// Function prototypes
char getMenuResponse(); // Function to allow user to navigate program.
void addContacts(vector<AddressBook>&); // Function to add contacts.

int find_smallest(const vector<AddressBook>& vec, int index);
void my_swap (AddressBook& obj_one, AddressBook& obj_two);
void sortFirstNames(vector<AddressBook>& list);

int main() {

// To operate, to avoid losing previous contacts, Open File first

vector<AddressBook> list;
bool run = true;

cout << "Welcome To My Address Book Program For Assignment 2!\n" << endl;

do {
switch (getMenuResponse()) {
case 'A': addContacts(list); break;
case 'D': dispContacts(list); break;
case 'M': sortFirstNames(list); break;
case 'O': openFile(list); break;
case 'S': saveFile(list); break;
case 'F': findContact(list); break;
case 'R': removeContact(list); break;
case 'E': editContact(list); break;
case 'Q': run = false; break;
default : cout << "That is NOT a valid choice" << endl;
}
} while (run);

cout << endl << "Program Terminated" << endl;

// system("PAUSE"); // Commented out so the program exits upon request
return EXIT_SUCCESS;
}

bool AddressBook::operator ==(const AddressBook& bok) {
return (firstname == bok.firstname && lastname == bok.lastname && addr == bok.addr && phone == bok.phone);
}

AddressBook& AddressBook::operator=(const AddressBook& bok) {
if(*this == bok)
return *this;
else
{
firstname = bok.firstname;
lastname = bok.lastname;
addr = bok.addr;
phone = bok.phone;
}
return *this;
}

void my_swap (AddressBook& obj_one, AddressBook& obj_two)//helping function one
{
AddressBook temp = obj_one;
obj_one = obj_two;
obj_two = temp;
}

int find_smallest(const vector<AddressBook>& vec, int index)//helping function two
{
int smallest_index = index;
AddressBook temp = vec [index];

for (unsigned int i = index; i < vec.size(); i++)
{
if(vec[i].firstname < temp.firstname)
{
smallest_index = i;
temp = vec[i];
}
}
return smallest_index;
}

void sortFirstNames(vector<AddressBook>& list)//selection sort algorithm{ascending}
{
for (unsigned int count = 0; count < list.size (); count++)
{
int ind_to_swap = find_smallest (list, count);
my_swap(list[count], list [ind_to_swap]);
}
}

void addContacts(vector<AddressBook>& list) {
AddressBook tmp; // Declare a temp contact that we will load before putting in the array.
char response;
string str; // Needed for cin.getline; we are going to use a char array.
bool run = true;

do {
system("cls");
cout << "Enter Contact Information" << endl;
cout << "Enter 'quit' at Name to exit." << endl << endl;

cout << "First Name: "; // Entering first name.
getline(cin, str);
tmp.firstname = str;
cout << endl;

if (str == "quit") break;

cout << "Last Name: "; // Entering last name.
getline(cin, str);
tmp.lastname = str;
cout << endl;

cout << "Address: "; // Entering Address
getline(cin, str);
tmp.addr = str;
cout << endl;

cout << "Phone Number: "; // Entering phone number.
getline(cin, str);
tmp.phone = str;
cout << endl;

// See if this record should be added to the array.
cout << "Add Contact to Address Book? (y/n) ";
cin >> response;
cin.ignore(256, '\n');
if (toupper(response) == 'Y') {
list.push_back(tmp);
cout << "Contact added!"<< endl;
}else {
cout << "Contact not added!" << endl;
}

} while (run);
system("cls");
}

char getMenuResponse() {
char response;
cout << endl << "Make your selection" << endl
<< "(A)dd contact, \n(D)isplay Contacts, \n(M)Sort By First Name, "
<< "\n(O)pen File, \n(S)ave File, "
<< "\n(F)ind Index Of Contact By First Name, \n(R)emove Contact,"
<< "\n(E)dit Contact, \n(Q)uit" << endl
<< "> ";
cin >> response;
cin.ignore(256, '\n');
// Clean-up up to 256 chars including the delimiter specified (\n, the endl)
// OR stop when the \n is encountered after removing it.
return toupper(response);
}
closed account (SECMoG1T)
But the sort function shouldn't display anything at all... seeing that you already got a display function in your original code, you could simply , display all your records before you sort 'em and after to view the differences, or you could modify the sort function to display something ... like a sorting message or jusy displaying the sorted records.

using your original code, coz I can seen your current code is missing some sections comparing it to your first one . Maybe a mod like this could work fir your case.


1
2
3
4
5
6
7
8
9
10
11
12
 void sortFirstNames(vector<AddressBook>& list)
   {
             std::cout <<"Before sorting records\n";/// added this here
             dispContacts (list); std::cout <<std::endl;
       for (unsigned int count=0; count <list.size (); count++) 
          {
               int ind_to_swap=find_smallest (list, count);
               my_swap(list[count], list [ind_to_swap]);
          }
            std::cout <<" Current sorted records\n";
            dispContacts (list);/// added this Too 
   }


Use the added code to debug the function itself.
Try see if it solved the deal... yeah,
Although a function call to such a function would be very costly especially for large no of records
Last edited on
Thanks so much for all of your help. The sort is working!
closed account (SECMoG1T)
Welcome :)
Topic archived. No new replies allowed.