Unable to access members of a class; SegFault - c++

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.

Related

Why do I get a segmentation fault when fetching this variable?

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;
}
}

Calling a base function from derived class function?

The class BaseSearch is the base function that I'm trying to call within the derived function (ValueSearch).
The code that I have in question specifically is under ValueSearch, calling BaseSearch::Print(line, title). The compiler errors I'm getting are:
I'm uncertain if I'm using inheritance correctly.
Error 1 error C2275: 'std::string' : illegal use of this type as an expression
BaseSearch.cpp
BaseSearch::BaseSearch()
{
}
BaseSearch::~BaseSearch()
{
}
void Print(string line, string title)
{
char c2 = '_'; //set character to blank value; defines the header row
char c = '_'; //set character to blank value; defines the searched row
int numHeader = 0; //sets the value of character for the header row
int numLine = 0; //sets the value of character for the searched row
c2 = line[numLine];
while (true) //force while loop
{
c = title[numHeader]; numHeader++; //header character is set to the title array defined as the entire header string above
if (c != ',')
{
cout << c; // couts the header until it reaches a ','
}
if (c == ',' || title.size() == numHeader) // if c reaches a ',' it will print the searched row
{
cout << ": ";
while (line.size() != numLine)
{
while (c2 != ',' && line.size() != numLine)
{
cout << line[numLine];
numLine++;
if (line.size() != numLine)
c2 = line[numLine];
else
break;
}
if (line.size() != numLine)
{
numLine++;
c2 = line[numLine];
cout << "\n";
break;
}
}
}
if (title.size() == numHeader) // if c reaches a null value, it breaks until other row is found.
{
cout << endl << endl; break;
}
}
}
BaseSearch.h
#ifndef BASESEARCH_H
#define BASESEARCH_H
#include <string>
class BaseSearch
{
public:
BaseSearch();
virtual ~BaseSearch();
virtual void Print(string, string);
};
Value Search.cpp
ValueSearch::ValueSearch()
{
string input;
}
ValueSearch::~ValueSearch()
{
//dtor
}
double ValueSearch::getInput()
{
cout << endl << "Enter the name of the company you would like to search for: ";
cin >> input;
return input;
}
void ValueSearch::ValueSearchFunc(int c, int x)
{
column = c;
// cout << "Enter the name of the company you would like to search for: ";
// getline(cin, input);
string line;
ifstream fs("Stock Database.csv");
string title;
getline(fs, title);
while (!fs.eof())
{
getline(fs, line);
string companyname = ""; //start as blank, then append
string a;
int commacount = 0; //how many commas have we passed
int ChrCount = 0; //counter for which character in the line we are looking at
while (line != "\0") //while the line does not equal to null value.
{
double price;
price = 0;
a = line[ChrCount]; //convert char c to a string (a) so that we can append
ChrCount++;
if (a == ",")
{
commacount++; //increases the comma count as a encounters a comma each time.
}
else if (commacount == column && (a != "N" && a != "/" && a != "A")) //if comma count is equal to the set column, it will append the string company name.
{
while (a != ",")
{
if (a != ",")
{
companyname.append(a);
a = line[ChrCount];
ChrCount++;
}
}ChrCount--;
price = stod(companyname);
}
else if (commacount > column) // if the comma count is any value larger than the column, breaks out of loop.
{
break;
}
if (input == 0)
{
break;
}
if (x == 1){
if (price >= input && price != 0) // if the appended company name is equal to the search input entered, it will cout the entire row.
BaseSearch::Print(line, title);
}
if (x == 2)
{
if (price <= input && price != 0) // if the appended company name is equal to the search input entered, it will cout the entire row.
BaseSearch::Print(line, title);
}//end if
}
}
}
ValueSearch.h
#ifndef VALUESEARCH_H
#define VALUESEARCH_H
#include <string>
#include "BaseSearch.h"
class ValueSearch : public BaseSearch
{
public:
ValueSearch();
~ValueSearch();
double getInput();
void ValueSearchFunc(int c, int x);
void Print(string,string) {BaseSearch::Print(string,string);}
protected:
private:
double input;
int column;
};
#endif
It seems you are a beginner of C++.I will show you an example code which will compile successfully.
BaseSearc.h:
#ifndef BASESEARCH_H
#define BASESEARCH_H
#include <string>
using namespace std;
class BaseSearch
{
public:
BaseSearch();
~BaseSearch();
void Print(string, string);
};
#endif
BaseSearch.cpp:
#include "BaseSearch.h"
#include <iostream>
BaseSearch::BaseSearch()
{
}
BaseSearch::~BaseSearch()
{
}
void BaseSearch::Print(string line, string title)
{
cout << "line:" << line << endl;
cout << "title:" << title << endl;
}
ValueSearch.h:
#ifndef VALUESEARCH_H
#define VALUESEARCH_H
#include <string>
#include "BaseSearch.h"
class ValueSearch : public BaseSearch
{
public:
ValueSearch();
~ValueSearch();
double getInput();
void ValueSearchFunc(int c, int x);
protected:
private:
double input;
int column;
};
#endif
ValueSearch.cpp:
#include "ValueSearch.h"
ValueSearch::ValueSearch()
{
}
ValueSearch::~ValueSearch()
{
}
double ValueSearch::getInput()
{
return input;
}
void ValueSearch::ValueSearchFunc(int c, int x)
{
//where is 'input' from?
//if (x == 1)
//{
// if (price >= input && price != 0)
// BaseSearch::Print(line, title);
//}
//if (x == 2)
//{
// if (price <= input && price != 0)
// BaseSearch::Print(line, title);
//}//end if
}
But I've no idea what ValueSearchFunc wants to do.
There is no realization of BaseSearch constructor/destructor in code. And Print function realization should be
void BaseSearch::Print(string line, string title)
{
//code
}

Why can't I access directly in vector iterator?

Why can't i do like this? In the below code, I can access from for loop, but not from outside loop?
class root
{
string name;
public:
root()
{
}
root(const string& okay)
{
name = okay;
}
void setRoot(const string& okay)
{
name = okay;
}
string getRoot()
{
return name;
}
~root ()
{
}
}; // class root
int main()
{
string a;
vector<root> Root;
vector<root>::iterator oley;
root okay;
for (int i=0; i<5;i++) //this is to add strings in vector
{
cin >> a;
okay.setRoot(a);
Root.push_back(okay);
}
for (oley=Root.begin(); oley!=Root.end(); oley++) //this is to print vectors in scren
{
cout << (*oley).getRoot() << endl;
}
oley = Root.begin();
cout << (*oley + 2).getRoot(); //this is error. What is required to make it legal?
return 0;
}
So, if we can access iterator from for loop, why can't we do so in non-looped codes?
cout << (*oley + 2).getRoot();
This is because of C++ operator precedence, *oley+2 is interpreted as (*oley) + 2 which is becomes root + 2
update
cout<<(*oley+2).getRoot();
to
cout<<(*(oley+2)).getRoot();
or
cout<<oley[2].getRoot();

Alternative to strcmp() to alphabetically sort strings

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;
}

no match for 'operator='

I have built a static stack of structures, and everything works - including creating an array of the structures. However, for some reason I can't set the top of the array to a structure.
In my .cpp file, in my push function, I keep erroring on the following line:
stackArray[top] = newStudent;
The error I am receiving is:
"51: no match for 'operator=' in '(((studentstack)this)->studentstack::stackArray + (+(((unsigned int)((studentstack*)this)->studentstack::top) * 24u))) = ((studentstack*)this)->studentstack::newStudent' "
I am including my code below.
Header file:
#ifndef studentstack_H
#define studentstack_H
#include <iostream>
#include <string>
using namespace std;
class studentstack {
private:
int size; // Stack size
int top; // Top of the Stack
struct student {
int ID;
string Name;
string Address;
double GPA;
};
student * stackArray; // Pointer to the stack
student * newStudent; // Pointer to the new student
public: //Constructor
studentstack(int);
// Copy Constructor
studentstack(const studentstack &);
//Destructor
~studentstack();
//Stack Operaations
void push(string, int, double, string);
void pop(int &);
bool isFull() const;
bool isEmpty() const;
};
#endif
studentstack.cpp
#include <iostream>
#include "studentstack.h"
using namespace std;
studentstack::studentstack(int SIZE) {
stackArray = new student[SIZE];
size = SIZE;
top = -1;
int ID = 0;
double GPA = 0;
}
studentstack::studentstack(const studentstack &obj) {
if (obj.size > 0)
stackArray = new student[obj.size];
else
stackArray = NULL;
size = obj.size;
for (int count = 0; count < size; count++)
stackArray[count] = obj.stackArray[count];
top = obj.top;
}
studentstack::~studentstack() {
delete [] stackArray;
}
void studentstack::push(string name, int id, double gpa, string address) {
if (isFull()) {
cout << "The stack is full.\n";
} else {
top++;
newStudent = new student;
newStudent-> Name = name;
newStudent-> ID = id;
newStudent-> Address = address;
newStudent-> GPA = gpa;
stackArray[top] = newStudent;
}
}
void studentstack::pop(int &id) {
if (isEmpty()) {
cout << "The stack is empty.\n";
} else {
id = stackArray[top].ID;
top--;
}
}
bool studentstack::isFull() const {
bool status;
if (top == size - 1)
status = true;
else
status = false;
return status;
}
bool studentstack::isEmpty() const {
bool status;
if (top == -1)
status = true;
else
status = false;
return status;
}
main.cpp
#include "studentstack.h"
#include <iostream>
#include <string>
using namespace std;
int main() {
string name;
int id, var;
string address;
double gpa;
studentstack s[20];
for(int x =0; x<20; x++) {
cout << "New Student Name: " << endl;
cin >> name;
cout << "ID: " << endl;
cin >> id;
cout << "GPA: " << endl;
cin >> gpa;
cout << "Address: " << endl;
cin >> address;
s.push(name, id, gpa, address)
}
cout << "Popping: "
for(int x = 0; x < 5; x++) {
s.pop(var);
cout <<var;
}
return(0);
}
You might want to cut down the example to a minimal piece of code showing the problem. What it comes down to is that you try to assign a student* to a an element in an array of student objects. A pointer to an object is different to an object:
stackArray[0] = new student(); // does NOT work
stackArray[0] = student();
Note, that object are created in C++ by a constructor and not necessarily involving new. When you construct and object using new you still create an object but you also allocate space for it on the heap. By default, objects are created wherever they are defined. For example, student() creates an object on the stack which is then assigned to an object in the memory of stackArray[0].
Not directly related to your question, but note that your main() cannot work. You declare an array of 20 studentstack elements:
studentstack s[20];
and later on you're doing:
s.push(/* ... */);
s.pop(/* ... */);
That doesn't make much sense. s is not a studentstack. It's an array of studentstacks. Arrays in C++ don't have member functions.