Why is this program crashing ? Did I wrongly allocate memory? - c++

Question
Design a class Employee with name and employee number. Derive Manager, Scientist and Laborer classes. The manager class has extra attributes title and dues. The scientist class has extra attribute number of publications. The Laborer class has nothing extra. The classes have necessary functions for set and display the information.
My solution
#include<iostream>
#include<cstring>
using namespace std;
class employee
{
protected:
char *name;
int number;
public:
employee()
{
cout<<"enter employee name \n";
cin>>name;
cout<<"enter employee number \n";
cin>>number;
}
void display()
{
cout<<"name \t"<<name<<endl;
cout<<"number \t"<<number<<endl;
// inside class function is a inline function
}
};
class manager: private employee
{
float due;
char *title;
public:
manager( )
{
cout<<"due\t "<<endl;
cin>>due;
cout<<"title\t"<<endl;
cin>>title;
fflush(stdin);
}
void display()
{
employee::display(); //inside class function is a inline function
cout<<"due\t"<<due<<endl;
cout<<"title\t"<<title<<endl;
//inside class function is a inline function
}
};
class labour :private employee
{
public:
void display()
{
employee::display(); //inside class function is a inline function
}
};
class Scientist :private employee
{
int number;
public:
Scientist()
{
cout<<"publication number "<<endl;
cin>>Scientist::number;
}
void display()
{
employee::display();
cout<<" pub number "<<Scientist::number<<endl;
fflush(stdin);
} //inside class function is a inline function
};
int main()
{
manager m;
m.display();
Scientist s;
s. display();
labour l;
l.display();
return 0;
}

You don't allocate any memory for title or name, so you can't read into them from std::cin. Instead of using char* you should use std::string which will do all of the allocation for you:
std::string title;
std::string name;

In the constructor of empolyee you read into an uninitialized char*. Therefore it does not point to a valid block of memory where you could store the entered name to. You could do
name = static_cast<char*>(malloc( 32 * sizeof(char) ));
to allocate memory such that name points to valid memory, but you always waste memory or do not have enough for the input. Also you have to free the memory in the destructor.
As Peter Schneider wrote in the comment of this answer, another option is to use arrays of a fixed size as a member, e.g.
char name[MAX_NAME_LENGTH];
with a e.g. preprocessor defined
#define MAX_NAME_LENGTH 64
at the top of your file. This way the copy constructor does his job. With pointers as members, you always have to write them yourself, otherwise, the original class instance and copied instance will have a member pointer pointing to the same memory. So if one the copied instance changes the name, the original instance will have a changed name, too.
The easiest solution would be to use a std::string instead of char*. It allocates memory on its own and you don't have to free anything and copying works fine, too.

Related

define book class with member function and store value

Can someone please help me with the below requirement
Class book that that contains attributes BookId, BookName, and Price. It also contain member function to input and show its attributes.
Write another class Writer that contains that contains the attributes of WriterName, Address and NumberofBooks written by him. It contains array of book objects as iys member. The length of array should be 5 to store the data of five books.
It should also contain a member function to input and display its attributes.
I found a solution on google with below code but it appears it is useful for my half requirement.
#include<iostream.h>
#include<stdio.h>
#include<conio.h>
class BOOK
{
int BOOKNO;
char BOOKTITLE[20];
float PRICE;
void TOTAL_COST(int N)
{
float tcost;
tcost=PRICE*N;
cout<<tcost;
}
public:
void INPUT()
{
cout<<"Enter Book Number ";
cin>>BOOKNO;
cout<<"Enter Book Title ";
gets(BOOKTITLE);
cout<<"Enter price per copy ";
cin>>PRICE;
}
void PURCHASE()
{
int n;
cout<<"Enter number of copies to purchase ";
cin>>n;
cout<<"Total cost is ";
TOTAL_COST(n);
}
};
void main()
{
BOOK obj;
obj.INPUT();
obj.PURCHASE();
getch();
}
To contain an instance of an object you declare a member of that type in your class:
class Writer
{
const size_t MAX_BOOKS_WRITTEN = 5U;
Book books_written[MAX_BOOKS_WRITTEN];
};
In the above class, "that contains that contains" an array of books written.

Pointer to a structure in an array of structures

So i need to get code of the structure#1 (e[0]) but i get the following error;
"error: request for member 'get_code' in 'emp1', which is of pointer type 'Employee*' (maybe you meant to use '->' ?)"
i don't really understand how to fix this. Plus, it's an assigment so i'm bound to use structures,and also, i don't know what "->" is, but if it's any operator or something, im not allowed to use it cause we haven't been taught that yet.
(Answers to the similar question suggest using -> so that doesnt work for me.)
i also tried using *(emp1).get_code()
#include <iostream>
#include <string.h>
using namespace std;
struct Employee{
private:
string code;
string name;
float salary;
public:
void set_code(string c){
code=c;
}
void set_name(string n){
name=n;
}
void set_sal(float s){
salary=s;
}
string get_code(){
return code;
}
string get_name(){
return name;
}
float get_sal(){
return salary;
}
};
int main(void) {
Employee e[2],*emp1,*emp2;
string c,n;
float s;
for (int i=0;i<2;i++){
cout<<"Enter code for employee "<<i+1;
cin>>c;
e[i].set_code(c);
cout<<"Enter name for employee "<<i+1;
cin>>n;
e[i].set_name(n);
cout<<"Enter salary for employee "<<i+1;
cin>>s;
e[i].set_sal(s);
}
*emp1=e[0];
cout<<emp1.get_code();
}
First of all, this line is not correct:
*emp1=e[0];
What your line does is assign the structure value 'e[0]' to the structure at pointer 'emp1'. However, the pointer 'emp1' is never initialized, so you'd end up writing in an invalid location.
What you need to write is:
emp1=&e[0];
That will actually set emp1 to the location of 'e[0]'.
Secondly, the symbol '->' is what you use when you want to access a member of a pointer.
In this case you should not write:
cout<<emp1.get_code();
But rather:
cout<<emp1->get_code();
The reason why you need to write that is that 'emp1' is a pointer. Thus, to access its member 'get_code', you need to use the symbol '->'.

File handling in c++ copying data to object of class

#include<iostream>
#include<string>
#include<fstream>
using namespace std;
class telephone
{
string name;
long number;
public :
void getdata();
void display();
};
void telephone :: getdata()
{
cout<<"Enter the name : ";
getline(cin,name);
cout<<"Enter the number : ";
cin>>number;
}
void telephone :: display()
{
cout<<"1. Name : "<<name<<endl;
cout<<"2. Number : "<<number<<endl;
}
int main()
{
fstream f;
telephone p,q;
f.open("dir.txt",ios::out);
p.getdata();
f.write((char*)&p,sizeof(telephone));
f.close();
f.open("dir.txt",ios::in);
while( f.read((char*)&q,sizeof(telephone)))
{
q.display();
}
f.close();
return 0;
}
I have written this code to write and read data from file in class object.It displays the output but shows some error.
OUTPUT :
Enter the name : rahul
Enter the number : 234546
1. Name : rahul
2. Number : 234546
*** Error in `./a.out': double free or corruption (fasttop): 0x08f861a8 ***
Aborted (core dumped)
I have tried by using file extension like .txt,.bin,.dat but it showed the same error.Please help me to remove this error.
Writing a telephone to a file as a binary blob will not work. telephone contains name and name is a std::string. A std::string does not typically contain the string data it represents; it contains a pointer to the string data.
So when you
f.write((char*)&p,sizeof(telephone));
what you actually wrote to the file was not the string data, but a pointer to the string data. This means that
f.read((char*)&q,sizeof(telephone));
reads back p's pointer to q and that means that p and q both point at the same string data. This is bad.
When p or q go out of scope and are destroyed, they destroy name, and name, like a good little std::string, and frees the memory it points at. This leaves the other object containing a std::string pointing at memory that has been freed, and sooner or later that other object will either be used and invoke undefined behaviour or be destroyed and attempt to free the previously freed memory. This is what is meant in the error message by "double free". The same memory has been freed twice.
In your case, if q is deleted before p, q releases the memory that both p and q point at leaving p pointing at an invalid memory location. A few nanoseconds later p is deleted and p cannot free the already freed memory.
To get around this you must ensure the contents of the std::string are written to the file and then read back. This is called serialization.
Typical solutions to this problem are to write the data to the file in a text format with << and read it back with >> (which may require you to implement the << and >> operators for your class)
class telephone
{
string name;
long number;
public :
void getdata();
void display();
friend std::istream & operator<<(std::istream & out, const telephone & tp);
friend std::ostream & operator>>(std::ostream & in, telephone & tp);
};
or add serialization functions to the class
class telephone
{
string name;
long number;
public :
void getdata();
void display();
bool serialize(std::iostream & out);
bool deserialize(std::iostream & in);
};
The writing of these functions is probably the point of this assignment, so I'll stop here. Don't worry. Both are approaches are exceedingly well documented online if you have trouble. I recommend starting with the first option. It is much easier to debug because you can read the text file to see if you got it wrong.

Not understanding what is being asked and how to type them?

I am having trouble understanding some parts of the question for this program and would like to know why and how to type the program. Here are the parts I'm unable to understand:
The third member variable is a pointer to a double, pquiz. This will be used to dynamically allocate an array which will hold a student's quiz grades.
(Did I do this correctly?)
The fourth member variable is a double holding the average value of the quiz grades.
The class should have a one parameter constructor which accepts an int and will dynamically allocate the array of double quiz grades. Or the class can >have a two parameter constructor which accepts both a string and an int.
The int is the number of quiz grades
The constructor uses the new operator to allocate memory for the array of quiz grades.
If there are two parameters, the string is the student's name.
The class needs the usual mutator, accessor functions and a destructor function.
The class has an additional function, average(), which calculates the average of all the quiz grades held in the array pointed to by pquiz. It returns the double average value.
I'm suppose to print a students name, number of tests the student took, and the average. Here is my program so far:
#include <iostream>
#include <string>
using namespace std;
class TestScore{
private:
string name;
int grades;
double *pquiz;
double average;
public:
TestScore();
void setName(string);
void setGrades(int);
void setAverage(double);
string getName();
int getGrades();
double getPquiz();
double getAverage();
};
TestScore::TestScore()
{
name="?";
grades=0;
pquiz=0;
average=0;
}
void TestScore::setName(string name1)
{
name=name1;
getline(cin,name1);
}
void TestScore::setGrades(int grades1)
{
grades=grades1;
}
void TestScore::setAverage(double average1)
{
average=average1;
}
string TestScore::getName()
{
return name;
}
int TestScore::getGrades()
{
return grades;
}
double TestScore::getAverage()
{
return average;
}
int main()
{
TestScore exam;
TestScore *ts=&exam;
string name;
int grade;
double *pquiz;
double average;
double total=0.0;
int count;
cout<<"Enter student name: ";
exam.setName(name);
cout<<"How many quizzes are there? ";
exam.setGrades(grade);
cin>>grade;
pquiz=new double[grade];
for(count=0; count<grade; count++)
{
cout<<"Quiz "<<(count+1)<<": ";
cin>>pquiz[count];
}
for(count=0; count<grade; count++)
{
total+=pquiz[count];
}
average=total/grade;
cout<<exam.getName()<<" has an average of "<<average<<endl;
delete [] pquiz;
pquiz=0;
return 0;
}
If I understand correctly member grades holds the length of the array pointed to by member pquiz. Whenever grades is set pquiz must also reflect new change (old array should be deleted, new one should be created). In constructor must only create the array. In setGrades() must delete old and create new.
Because member pquiz is controlled (or owned) by the class TestScore it's only logical that it should be deleted when object TestScore is deleted (or in our lingo "when it goes out scope"). This is done in class destructor, which you should add to the class.
According to text there should be one more member function, average(), that calculates the average and stores the value in member average. This member should be renamed, for the sake of your sanity.

Newbie Site fault issue C++

I'm working on a project where I create bank accounts and able to deposit and withdraw. I am to create two bank account and two people- one one the stack and the other on the heap. I should deposit and withdraw into each twice and get the balance print the name and ID and account numbers. At the moment I'm get what I believe is a site fault , reading or writing to protected memory. I've left comments on where I think the errors lie. I would appreciate any help. Thanks.
#include <iostream>
#include <string>
using namespace std;
class BankAccount {
private:
double *balance;
int *accountNumber;
public:
BankAccount(){//default constructor
*balance = 0.0;/***This is where is says the Access violation lies*/
*accountNumber = 0;
}
BankAccount(double bal, int acctNum){//constructor
balance = new double(bal);
accountNumber = new int(acctNum);
}
~BankAccount() {delete balance; delete accountNumber;}
void Deposit(double amt) {
*balance = *balance + amt;
}
virtual double GetBalance() {
return *balance;
}
virtual double GetAccountNumber() {
return *accountNumber;
}
virtual double Withdraw(double amt) {
*balance = *balance - amt;
return *balance;
}
};
class Person {
string *name;
int *ID;
public:
Person(){//default constructor
*name = "name not yet defined";
*ID = 0;
}
Person(string nameIn, int idIn){//constructor
name = new string(nameIn);
ID = new int(idIn);
}
virtual int GetID() {
return *ID;
}
virtual string GetName() {
return *name;
}
};
class NamedBankAccount: public BankAccount {
private:
Person *owner;
public:
NamedBankAccount(){
}
NamedBankAccount(Person *p): owner(p){/***This is where is says the Access violation lies*/
p = new Person();
}
~NamedBankAccount(){delete owner;}
Person getPerson() {
return *owner;
}
};
int main() {
Person *q = new Person("Joe", 54321);
cout << q->GetName() << endl;
cout << q->GetID() << endl;
NamedBankAccount nba1;/***This is where is says the Access violation lies*/
NamedBankAccount *nba2 = new NamedBankAccount(q);
nba1.Deposit(50);
nba1.Deposit(50);
nba1.Withdraw(25);
cout << nba1.GetBalance() <<endl;//should print 75
nba2->Deposit(60);
nba2->Deposit(60);
nba2->Withdraw(20);
cout << nba2->GetBalance() << endl;//should print 100
getchar();
return 0;
}
Do not use pointers here. Just have those strings and integers be member variables. For the specific problem - you haven't allocated any memory before assignment in the default constructor.
Do something like:
class BankAccount {
private:
double balance;
int accountNumber;
public:
BankAccount() :
balance( 0.0 ),
accountNumber( 0 ) {}
// ...
Edit:
Couple of more points about your code:
make use of initialization list in the constructors instead of assignment to member variables - this avoids two-step process of first default-initializing the members and then assigning to them
base polymorphic classes should have virtual destructors, so instances of derived classes could be properly destroyed via pointer to base
polymorphic types usually need to follow the rule of three to avoid slicing
do not make all member functions of a base class virtual, only those you want derived classes to override
think before making a type polymorphic - do you really have bank accounts without owners? Maybe that can be just a value type?
make accessor methods const, so you can get information from const instances
check for errors (you sure don't want to allow withdrawals from zero or negative balance accounts)
"do not use pointers" is a bit strong but what Nikolai means is that member variables shouldn't be pointers to base types but just those types
i.e. in BankAccount, balance should just be an double and not a double* like wise for the others
or have BankAccount() call BankAccount(0.0, 0) as that will allocate the fields right like wise for Person() but unexpectedly this doesn't do what i thought it would in C++ as Karl Knechtel remarks
You are dereferencing an uninitialized pointer, if you change their places it would still do the same thing.
You see, c++ (and c) uses pointers as addresses to memory, if you don't initialize then they will point to anywhere in memory, so dereferencing will PROBABLY cause access violation (probably because you don't know were your pointer points to).
The correct way would be:
BankAccount(){//default constructor
balance = new double; // Initialize pointer (make it points to a valid memory address)
*balance = 0.0; // Give a value to the variable where balance is pointing
accountNumber = new int; // Initialize pointer (make it points to a valid memory address)
*accountNumber = 0; // Give a value to the variable where balance is pointing
}
OR, if you want to allocate memory latter:
BankAccount(){//default constructor
balance = 0; // Make it point to address 0 (conventional value meaning it is uninitialized)
accountNumber = 0; // Make it point to address 0 (conventional value meaning it is uninitialized)
}
Of course, as stated, in your case it would probably be best to use normal variables and not pointers. You should read more about pointers before using them, they can be a pain (I think I speak here on behalf of 99.999% of C and C++ programmers, we've all been there).