I am trying to create a function that allows me to type a name and return that employees information found in the struct. /.......................................................................
// info (ss_number,etc..)
struct employees {
int ss_number;
int dob; //date of birth
string f_name;
string l_name;
string state;
};
void print_person(employees e)
{
cout<<e.ss_number<<" "<<e.dob<<" "e.f_name<<" "<<e.l_name<<" "<<e.state;
}
void search(employees array[])
{
string first;
string last;
cout << "Enter name"; //Example Jack Patton
cin >> first >> last;
for(int i = 0; i < 10; i++) {
if(array[i].f_name == first && array[i].l_name == last) {
print_person(array[i]);
}
}
}
void main()
{
employees array[10];
search(array);
}
*t is better to place the request for the name outside the function. The function should do only the search.
It could be defined the following way
const employee * search( const employees array[], size_t n,
const std::pair<std::string, std::string> &name )
{
const employees *first = array;
while ( first != array + n &&
!( first->f_name == name.first && first->l_name == name.second ) )
{
++first;
}
return first;
}
And in main it could be called the following way (take into account that main shall have return type int):
int main()
{
const size_t N = 10;
employees array[N];
// filling the array
std::pair<std::string, std::string> name;
cout << "Enter name"; //Example Jack Patton
cin >> name.first >> name.second;
const employees *emp = search( array, N, name );
if ( emp != array + N )
{
print_person( *emp );
}
//...
}
Or you could use standard algorithm std::find_if with a predicate.
At the same time function print_person should be defined as
void print_person( const employees &e)
{
cout<<e.ss_number<<" "<<e.dob<<" "e.f_name<<" "<<e.l_name<<" "<<e.state;
}
What you have is mostly fine except that you never initialized any values for your array.
You could read them in from a file, but in the meantime write this and it will work (thanks M2tM for the data):
employees array[10] =
{ { 100, 1985, "John", "Edwards", "AB" }
, { 101, 1960, "Mike", "Thomas", "CA" }
/* fill in more rows if you want */
};
Other issues: in print_person you are missing an << before e.f_name ; and void main() should be int main().
This requires C++11 and fulfills your requirements. Notice I switched to vector (since you're using string you are using C++), and am using a built in algorithm with a lambda. C++ has a lot of built in functionality in the standard libraries to make this sort of thing much easier.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
struct Employee
{
int socialSecurtyNumber;
int yearOfBirth;
string firstName;
string lastName;
string state;
};
vector<Employee>::iterator search(vector<Employee> &employees, const string &first, const string &last)
{
return find_if(begin(employees), end(employees), [&](const Employee& employee){
return employee.firstName == first && employee.lastName == last;
});
}
int main()
{
vector<Employee> employees{
{ 100, 1985, "John", "Edwards", "AB" },
{ 101, 1960, "Mike", "Thomas", "CA" },
{ 102, 1992, "George", "Flunky", "FL" },
{ 103, 1983, "Tweet", "Johnson", "AB" },
{ 104, 1968, "Michael", "Jordan", "OH" },
};
string first;
string last;
cout << "Enter name: "; //Example Jack Patton
cin >> first >> last;
auto employee = search(employees, first, last);
if (employee != end(employees)){
cout << "FOUND! SSN: " << employee->socialSecurtyNumber << " YOB: " << employee->yearOfBirth << endl;
}else{
cout << "NOT FOUND!" << endl;
}
}
Related
I am pulling names as strings from a file, create a Person *p object, and put it into an array.
Then to search the array for a name but when I try to fetch the name I get a segmentation fault.
Why is this segmentation fault happening, and what can I do to fix it?
#include <iostream>
#include <string>
using namespace std;
class Person {
private:
string firstName;
string lastName;
string phoneNumber;
public:
Person();
Person(string f, string l, string n);
~Person(void);
void setName()
{
}
string getFirstName()
{
return firstName;
}
string getLastName()
{
return lastName;
}
string getNumber() { return phoneNumber; }
void print();
};
Array creation.
{
ifstream file;
file.open("phonebook.txt");
if (!file.is_open()) //Check for File Error.
{
cerr << "Failed to open file" << endl;
exit(1);
}
//Get Array Size
string line;
while (getline(file, line))
{
count++;
}
file.close();
//Create an array
Person *arrList[count];
buildArray(arrList, count);
if (uInput == "a" || uInput == "A") //To add
{
int x = addPerson();
if (x == 1)
{
count++;
}
delete[] arrList;
}
void buildArray(Person *arr[], int size)
{
string f, l, n;
ifstream file;
file.open("phonebook.txt");
for (int i = 0; i < size; i++)
{
file >> f >> l >> n;
Person *p = new Person(f, l, n);
arr[i] = p;
delete p;
}
}
The search, This is the part that has the trouble. I have tried a few different things including creating 2 Persons, and comparing their parts but whenever it goes into the .h it can not return the name.
if (uInput == "s" || uInput == "S")
{ //To Search
string f, l;
cout << "Find Who (Firstname Lastname) " << endl;
cin >> f >> l;
Person *n = new Person(f, l, "");
int i = 0;
bool found = false;
while (i <= count && found == false)
{
Person *p = new Person("", "", "");
p = arrList[i];
if (p->getFirstName() == n->getFirstName() && p->getLastName() == n->getLastName())
{
arrList[i]->print();
found = true;
delete p;
delete n;
}
i++;
}
while (i == count && found == false)
{
cout << "No results found. " << endl;
found = true;
}
}
Okay so I have an array like this:
class name {
public:
string first;
int last;
name(string a, int b){
first = a;
last = b;
}
};
name arr[] { { "John", 1 }, { "Jane", 2 }, { "Dick", 3 }, { "John", 1 }, { "Jane", 2 } };
For now I am only able to print them all out like this:
int main() {
int icount = sizeof(arr) / sizeof(name);
for (int i = 0; i < icount; i++){
cout << arr[i].first << " " << arr[i].last << endl;
}
}
Output will be like this:
John 1
Jane 2
Dick 3
John 1
Jane 2
However I need merge any similar results, meaning if the name is the same I need to add up the numbers behind them. The desired output should be like this:
John 2
Jane 4
Dick 3
Is there any function I can use to merge them or how should I go about doing it?
Here is another variant:
#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;
class name {
public:
string first;
int last;
name(string a, int b);
};
name::name(string a, int b) : first(a), last(b)
{
}
int main(int argc, char **argv)
{
string names[] =
{
"John", "Jane", "Dick", "John", "Jane"
};
int values[] =
{
1, 2, 3, 1, 2
};
vector<name> people;
for (int i = 0; i < sizeof(names) / sizeof(*names); ++i)
{
people.push_back(name(names[i], values[i]));
}
map<string, int> unique_people;
for (vector<name>::const_iterator it = people.begin(),
end = people.end(); it != end; ++it)
{
if (unique_people.count(it->first) != 0)
{
unique_people[it->first] += it->last;
}
else
{
unique_people.insert(pair<string, int>(it->first, it->last));
}
}
for (map<string, int>::const_reverse_iterator it = unique_people.rbegin(),
end = unique_people.rend(); it != end; ++it)
{
cout << it->first << " " << it->second << endl;
}
return 0;
}
Since you are using C++ you can use Map to finish your job.
Here is the complete program you need.
#include <iostream>
#include <map>
using namespace std;
map<string, int> mer;
class name
{
public:
string first;
int last;
name (string a, int b)
{
first = a;
last = b;
}
};
name arr[] { { "John", 1 }, { "Jane", 2 }, { "Dick", 3 }, { "John", 1 }, { "Jane", 2 } };
void merge()
{
int icount = sizeof(arr) / sizeof(name);
for (int i = 0; i < icount; i++)
{
if (mer.count(arr[i].first) > 0)
{
mer[arr[i].first]++;
}
else
{
mer[arr[i].first] = 1;
}
}
}
int main()
{
int icount = sizeof(arr) / sizeof(name);
merge();
map<string,int>::iterator it;
for(it = mer.begin(); it != mer.end(); it++)
{
cout << it->first << " " << it->second << endl;
}
return 0;
}
This will print the result of what you expected. Of course it will print in reverse order. You can use reverse iterator to get the desired result.
I'm currently writing a program that will help a college keep track of which students are in what clubs. This code will be pasted into existing code that works, as provided by my professor.
Could someone please look my code over, and help me work through my mistakes? I included comments to explain what everything should do.
Also, please note this is an assignment and I cannot change anything about the class. I'm also a beginner, so keep it simple, please. Your help will be extremely appreciated beyond all measure.
class Club
{
public:
Club();
Club(Club &c);
Club(string cname);
void addMember(string name);
void removeMember(string name);
string getClubName() const;
string setClubName(const string& nameOfClub);
void loadClub();
bool isMember(string& name) const;
string getAllMembers() const;
friend Club mergeClubs(Club& c1, Club& c2);
~Club();
private:
string *members;
int numMembers;
string clubName;
};
Club::Club()
{
clubName = "";
numMembers = 0;
}
Club::Club(Club &c)
{
numMembers = c.numMembers;
members = new string [numMembers];
for (int i = 0; i < numMembers; i++)
{
members[i] = c.members[i];
}
//copy constructor
//watch out for memory leaks
}
Club::Club(string cname)
{
clubName = cname;
//cname should be saved as the club's name in the clubName variable
}
void Club::addMember(string name)
{
string *m;
m = new string [numMembers];
string *members = m;
for (int i = 0; i < numMembers; i++)
{
for (int j = 0; j < name.length(); i++)
{
m[i] = name[j];
}
}
delete [] m;
//adds new member to the club
//records their name in the members variable
//may need a dynamic array to make this work, watch for memory leaks!
}
void Club::removeMember(string name)
{
string *m;
m = new string [numMembers];
string *members = m;
for (int i = 0; i < numMembers; i++)
{
if ( m[i] == name)
{
m[i] = "";
}
}
delete [] m;
//deletes the person from the array in members
//will do nothing if the person is not in the array to begin with
//may require dynamic array to make this work- watch for memory leaks!
//if the person's name appears more than once, just delete the first instance
}
string Club::getClubName() const
{
return clubName;
//getter of clubName
}
string Club::setClubName(const string& nameOfClub)
{
return clubName = nameOfClub;
//setter of clubName
}
void Club::loadClub()
{
//should print "tell me the name of the next member of the club"
//reads into the variable name
//uses addMember() to add that person to the club
//the input should include up to the line break as the name, so it should take in "jane doe" as an entry
//keeps asking for more names until the user enters a blank entry
string name;
do
{
cout << "Tell me the name of the next member of the club, ";
cout << "or submit a blank entry to stopent ering names." << endl;
getline(cin, name, '\n');
addMember(name);
} while (name != "");
}
bool Club::isMember(string& name) const
{
/*for (int i = 0; i < numMembers; i++)
{
for (int j = 0; j < name.length(); j++)
{
if (members[i] == name)
{
return true;
}
else
{
return false;
}
}
}*/
for (int i = 0; i < numMembers; i++)
{
if (members[i] == name)
{
return true;
}
return false;
}
//returns true if the person is a member of the club, false otherwise
}
string Club::getAllMembers() const
{
for (int i = 0; i < numMembers; i++)
{
return members[i];
cout << ", ";
}
cout << endl;
//returns a string of all the names of the members of the club
//commas and spaces separating every entry of the list
//should not be a comma following the last name in the list
}
Club mergeClubs(Club& c1, Club& c2)
{
//creates a new club from 2 existing clubs
//combined club name should be Club 1/Club 2
Club temp;
temp.clubName = c1.clubName + "/" + c2.clubName;
return temp;
}
Club::~Club()
{
delete [] members;
//destructor
//watch out for memory leaks
}
For some reason I cannot fathom I have (mostly) corrected this program for you. There are still some nasty things like passing copies of strings into const functions but fixing these would be mere optimisations. At least this program is logically correct.
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
#include <sstream>
using namespace std;
class Club
{
public:
Club();
Club(const Club &c);
Club(string cname);
void addMember(string name);
void removeMember(string name);
string getClubName() const;
string setClubName(const string& nameOfClub);
void loadClub();
bool isMember(const string& name) const;
string getAllMembers() const;
friend Club mergeClubs(Club& c1, Club& c2);
~Club();
private:
vector<string> members;
string clubName;
};
Club::Club()
: members()
, clubName()
{
}
Club::Club(const Club &c)
: members(c.members)
, clubName(c.clubName)
{
}
Club::Club(string cname)
: members()
, clubName(cname)
{
}
void Club::addMember(string name)
{
members.push_back(name);
}
void Club::removeMember(string name)
{
members.erase(remove(members.begin(), members.end(), name), members.end());
}
string Club::getClubName() const
{
return clubName;
//getter of clubName
}
string Club::setClubName(const string& nameOfClub)
{
return clubName = nameOfClub;
//setter of clubName
}
void Club::loadClub()
{
//should print "tell me the name of the next member of the club"
//reads into the variable name
//uses addMember() to add that person to the club
//the input should include up to the line break as the name, so it should take in "jane doe" as an entry
//keeps asking for more names until the user enters a blank entry
string name;
do
{
cout << "Tell me the name of the next member of the club, ";
cout << "or submit a blank entry to stopent ering names." << endl;
getline(cin, name, '\n');
addMember(name);
} while (name != "");
}
bool Club::isMember(const string& name) const
{
return find(members.begin(), members.end(), name) != members.end();
}
string Club::getAllMembers() const
{
stringstream result;
vector<string>::const_iterator b = members.begin(), e = members.end();
for (bool comma = false ; b != e; ++b, comma = true)
{
if (comma) {
result << ", ";
}
result << *b;
}
return result.str();
}
Club mergeClubs(Club& c1, Club& c2)
{
Club temp(c1.clubName + "/" + c2.clubName);
struct memberAdd {
Club& _club;
memberAdd(Club& club) : _club(club) {}
void operator()(const string& member) {
_club.addMember(member);
}
};
for_each(c1.members.begin(), c1.members.end(), memberAdd(temp));
for_each(c2.members.begin(), c2.members.end(), memberAdd(temp));
return temp;
}
Club::~Club()
{
//destructor
//watch out for memory leaks
}
int main()
{
Club boys("red");
boys.addMember("Ben");
boys.addMember("Paul");
Club girls("blue");
girls.addMember("Lucy");
girls.addMember("Hermione");
Club unisex = mergeClubs(boys, girls);
cout << unisex.getClubName() << " has the following members: " << unisex.getAllMembers() << endl;
}
Some initial comments:
The copy constructor should take a const Club& like this:
Club(const Club& club)
members and numMembers are anachronistic. Use a std::vector for members and drop the numMembers altogether (std::vector has a size() method).
Club::Club does not initialise members or numMembers. This will result in a possible crash in the destrutor. This would be solved if you replaced them with a vector.
the logic in addMember does not make sense.
nor in removeMember
isMember should take a const string& and you would be well advised to write it in terms of std::find() (#include <algorithm>)
I could go on...
stuType Class:
#include<iostream>
#include<cstring>
using namespace std;
#ifndef STUTYPE
#define STUTYPE
class stuType {
private:
string fname;
string lname;
string social;
float gpa;
public:
stuType(void) {
fname = "no_fname";
lname = "no_lname";
social = "no_social";
gpa = 0.0;
}
stuType(string fname_in, string lname_in, string social_in, float gpa_in) {
fname = fname_in;
lname = lname_in;
social = social_in;
gpa = gpa_in;
}
~stuType() {
//Nothing needs to be added here.
}
void set_fname(string new_fname) {
fname = new_fname;
}
void set_lname(string new_lname) {
lname = new_lname;
}
void set_ssn(string new_ssn) {
social = new_ssn;
}
void set_gpa(float new_gpa) {
gpa = new_gpa;
}
string get_fname(void) {
return fname;
}
string get_lname(void) {
return lname;
}
string get_ssn(void) {
return social;
}
float get_gpa(void) {
return gpa;
}
friend istream & operator>>(istream &in, stuType &stu) {
in>>stu.fname;
in>>stu.lname;
in>>stu.social;
in>>stu.gpa;
return in;
}
};
#endif
Sort.cpp:
#include<iostream>
#include<fstream>
#include<cstdlib>
#include<cstring>
#include"stuType.h"
using namespace std;
/*Loads the elements of the object instance with data from the input file.*/
void load(istream &input, stuType Student[], int *size);
/*Used in combination with the shellSort method to exchange the values of two variables in the class object.*/
void exchange(stuType &a, stuType &b);
/*Sorts the objects in ascending order by comparing the values of the lname strings between object indices.*/
void shellSort(stuType Student[], int size);
int main() {
stuType Student[10];
int size;
char inputFile[200];
char outputFile[200];
ifstream input;
ofstream output;
cout<<"[INPUT_FILE]: ";
cin>>inputFile;
cout<<"[OUTPUT_FILE]: ";
cin>>outputFile;
input.open(inputFile);
output.open(outputFile);
if (input.fail()) {
cerr<<"\n[FILE] Error opening '"<<inputFile<<"'"<<endl;
exit(1);
}
if (output.fail()) {
cerr<<"\n[FILE] Error opening '"<<outputFile<<"'"<<endl;
exit(1);
}
load(input, Student, &size);
shellSort(Student, size);
return 0;
}
void load(istream &input, stuType Student[], int *size) {
int length = 0, i = 0;
float gpa;
string social;
string fname;
string lname;
while(input >> social >> fname >> lname >> gpa) {
cout<<"[Node::Load] Setting 'social' for index ["<<i<<"] to "<<social<<endl;
Student[i].set_ssn(social);
cout<<"[Node::Load] Setting 'fname' for index ["<<i<<"] to "<<fname<<endl;
Student[i].set_fname(fname);
cout<<"[Node::Load] Setting 'lname' for index ["<<i<<"] to "<<lname<<endl;
Student[i].set_lname(lname);
cout<<"[Node::Load] Setting 'gpa' for index ["<<i<<"] to "<<gpa<<endl;
Student[i].set_gpa(gpa);
cout<<"[Node::Load] Incrementing 'length'..."<<endl;
length++;
cout<<"[Node::Load] Incrementing 'i'..."<<endl;
i++;
}
cout<<"==================================="<<endl;
for (int i = 0; i<length; i++) {
cout<<"[ENTRY] Index: "<<i<<" | SSN: "<<Student[i].get_ssn()<<" | fname: "<<Student[i].get_fname()<<" | lname: "<<Student[i].get_lname()<<" | gpa: "<<Student[i].get_gpa()<<endl;
}
cout<<"==================================="<<endl;
*size = length;
}
void exchange(stuType &a, stuType &b) {
stuType *temp;
*temp = a;
a = b;
b = *temp;
delete temp;
}
void shellSort(stuType Student[], int size) {
int gap = size/2;
bool passOK;
while(gap>0) {
passOK = true;
for(int i = 0; i<size-gap; i++) {
if (strcmp(Student[i].get_lname(), Student[i+gap].get_lname)>0) {
cout<<"[Node::Sort] Exchanging Index ["<<i<<"] with Index ["<<i+gap<<"]..."<<endl;
exchange(Student[i], Student[i+gap]);
passOK = false;
} else if (strcmp(Student[i].get_lname(), Student[i+gap].get_lname())==0) {
if (strcmp(Student[i].get_fname(), Student[i+gap].get_fname())>0) {
cout<<"[Node::Sort] Exchanging Index ["<<i<<"] with Index ["<<i+gap<<"]..."<<endl;
exchange(Student[i], Student[i+gap]);
passOK = false;
}
}
}
if (passOK) {
gap /= 2;
}
}
}
strcmp() expects to receive a character array to do the comparison, but since I am using strings, I cannot do that. What is an alternative? The variable 'lname' needs to be compared and should return true if Student[i].get_lname() is greater than Student[i+gap].get_lname(). The exchange function will then be called and exchange the values of the object's local variables. The objects should be sorted in ascending order based on the value of the 'lname' variable and the 'fname' variable should only be referenced if the two 'lname's being compared are the same.
C++ strings provide implementations of operators < and >, so you can use them instead of strcmp:
std::string a = "hello";
std::string b = "world";
if (a < b) {
cout << a << " is less than " << b << endl;
}
I have a program where I am setting up a closed hash table. In each Element of the Hash table, there is a Student class which holds varies members (name, id, year, etc.). I am simply trying to print out what has been added to my array, but I keep getting a SegFault, and I don't know why. It is only in my print function, though. I have copied the line of code to my other functions or put them in different classes, and they work there, but not when I try to print from my print function. I am at the end of my rope, trying to figure out why I can access the memory location of each member, but not it's actual value.
Here is my program:
main.cpp:
using namespace std;
#include <cstdlib>
#include "hash.h"
int main()
{
string temp1;
string temp2;
string temp3;
string temp4;
string temp5;
string temp6;
Hash h;
do{
cout << "set> ";
cin >> temp1;
//Checking for quit command.
if(temp1.compare("quit") == 0)
{
return 0;
}
//checking for add command.
else if(temp1.compare("add") == 0)
{
cin >> temp2;
cin >> temp3;
cin >> temp4;
cin >> temp5;
cin >> temp6;
Student *s1 = new Student(temp2, temp3, temp4, temp5, temp6);
Element e1(s1);
h.add(e1);
}
//checking for remove command.
else if(temp1.compare("remove") == 0)
{
int r;
cin >> r;
h.remove(r);
}
//checking for print command.
else if(temp1.compare("print") == 0)
{
h.print();
}
//Anything else must be an error.
else
{
cout << endl;
cout << "Error! "<< endl;
}
}while(temp1.compare("quit") != 0);
}
hash.h:
#include <string>
#include <iostream>
#include <cstdlib>
using namespace std;
// Student Class
class Student{
private:
string firstName;
string lastName;
string id;
string year;
string major;
public:
//Constructor
Student(string a, string b, string c, string d, string e);
friend class Element;
friend class Hash;
};
//Element class
class Element{
private:
Student *data;
public:
int getKey();
Student* getData();
void printStudent();
//Constructor
Element(Student *e)
{
data = e;
};
friend class Hash;
};
class Hash{
private:
Element **array;
public:
void add(Element);
void print();
void remove(int);
//Constructor
Hash()
{
array = new Element *[10];
};
friend class Student;
};
hash.cpp:
#include "hash.h"
//The Constructor for Student
Student::Student(string a, string b, string c, string d, string e)
{
firstName = a;
lastName = b;
id = c;
year = d;
major = e;
}
//getKey function for Element Class
int Element::getKey()
{
int key = atoi(getData()->id.c_str());
return key;
}
Student* Element::getData()
{
return data;
}
void Element::printStudent()
{
string c = data->firstName;
cout<< "(" << c << ")";
}
//The add command
void Hash::add(Element e1)
{
int x = e1.getKey()%10;
int i = 0;
if(array[x] == NULL || array[x]->getData() == NULL)
{
array[x] = &e1;
}
else
{while(array[x] != NULL || array[x]->getData() != NULL)
{
x=(x+(i*i))%10;
if(array[x] == NULL || array[x]->getData() == NULL)
{
array[x] = &e1;
break;
}
else
{
i++;
}
}}
}
//The remove command
void Hash::remove(int n)
{
Element e2(NULL);
for(int j = 0; j<10; j++)
{
if(n == array[j]->getKey())
{
array[j] = &e2;
cout << "true" << endl;
break;
}
}
cout << "false" << endl;
}
//The Print command
void Hash::print()
{ int k = 0;
while(k<10)
{
if(array[k] == NULL)
{
cout << "(NULL)";
}
else if(array[k]->getData() == NULL)
{
cout << "(DEL)";
}
else
{
cout << "(" << array[k]->getData()->firstName << ")";
}
k++;
}
cout << endl;
}
Thank you for your help.
You have dangling pointers.
This function gets a temporary copy of an Element, calling it e1.
//The add command
void Hash::add(Element e1)
{
It then stores the address of this local variable.
array[x] = &e1;
And when Hash::add leaves scope, e1 no longer exists.
}
array[x] now points to memory that is no longer Element e1.
The general problem you are facing is that you have designed a Hash class that maintains pointers to objects, but has little control or knowledge regarding when those objects get destroyed.
You will need to personally ensure that objects added to your Hash last at least as long as the Hash does.
Simplest solution for your problem could be to store Element instances in Hash by value not by pointers. So:
class Hash{
private:
Element *array;
public:
void add(Element);
void print();
void remove(int);
//Constructor
Hash()
{
array = new Element[10];
};
friend class Student;
};
Now when you store new element or remove existing you copy them:
array[x] = e1; // not &e1 anymore
This is not very good practice, but at least could change your program in some workable state with minimal changes.