This function is supposed to take care of updating the file after calling the respective functions for depositing or withdrawing from a user account. But it fails to do just that. I've checked as much as I can and all the other functions seem to be doing their jobs properly. I've traced it down to the specific lines where the program seems to fail.
int pos = (-1) * static_cast<int>(sizeof(ac));
File.seekp(pos, ios::cur);
//File.write((char *)&ac, sizeof(BankAccount));
File.write(reinterpret_cast<char *>(&ac), sizeof(BankAccount));
Yes, these are two versions of the line because I don't fully understand how either of them work. (First version is mine, second line is from a sample program we were given)
void makeDepositOrWithdraw(int option)
{
int num;
cout << "\nEnter account number: ";
cin >> num;
int amt;
bool found = false;
BankAccount ac;
SavingsAccount save;
fstream File;
File.open("Account.dat", ios::binary | ios::in | ios::out);
if (!File)
{
cout << "Cannot retrieve database right now. Try again later";
return;
}
while (!File.eof() && found == false)
{
File.read(reinterpret_cast<char *>(&ac), sizeof(BankAccount));
if (ac.getAccountNo() == num)
{
ac.displayAcc();
if (option == 1)
save.makeDeposit();
if (option == 2)
save.makeWithdrawal();
int pos = (-1) * static_cast<int>(sizeof(ac));
File.seekp(pos, ios::cur);
//File.write((char *)&ac, sizeof(BankAccount));
File.write(reinterpret_cast<char *>(&ac), sizeof(BankAccount));
cout << "__________________________________"
<< "\nRecord updated ";
found = true;
}
}
File.close();
if (!found)
cout << "Record not found";
}
EDIT: I'm sorry for being really bad at explaining this. The initial creation of a new account works. But trying to make additional deposit doesn't run into any error, the variables are being properly updated all the way up to the main BankAccount class. But nothing gets updated in the already existing account in the .dat file. Program still executes without any error.
I'm assuming if I understand the problem with the depositing part, I'll be able to solve the problem with withdrawing too, as both are handled in the same function.
#include <iostream>
#include <fstream>
#include <cctype>
#include <iomanip>
using namespace std;
class BankAccount
{
private:
float Balance, ServChargePerMonth, AnnualInterestRt, DepoAmt, WithdrwAmt;
int NoOfDepositPerMonth, NoOfWithdrawalPerMonth, AccountNo;
char Name[50], type;
public:
virtual void makeDeposit()
{
Balance += DepoAmt; //adding argument to acc bal
NoOfDepositPerMonth++; //incrementing noOfDeposit
};
virtual void makeWithdrawal()
{
Balance -= WithdrwAmt; //subtracting argument from acc bal
NoOfWithdrawalPerMonth++; //incrementing noOfWithdrawal
};
virtual void createAcc()
{
cout << "\nEnter your account number: ";
cin >> AccountNo;
cout << "\nEnter your full name: ";
cin.ignore();
cin.getline(Name, 50);
cout << "\nEnter the type of Account (C for current or S for savings): ";
cin >> type;
type = toupper(type);
cout << "\nEnter initial deposit amount: ";
cin >> Balance;
cout << "___________________________________________________________"
<< "\n\nAccount created." << endl;
};
void displayAcc()
{
cout << "\nAccount number: " << AccountNo
<< "\nAccount holder name: " << Name
<< "\nType of account: " << type
<< "\nAccount balance: $" << Balance
<< "\nTotal number of deposits: " << NoOfDepositPerMonth
<< "\nTotal number of withdrawals: " << NoOfWithdrawalPerMonth
<< "\nService Charge: $" << ServChargePerMonth << endl;
};
//getters
float getBalance() { return Balance; }
float getDepoAmt() { return DepoAmt; }
int getNoOfDeposit() { return NoOfDepositPerMonth; }
int getNoOfWithdraw() { return NoOfWithdrawalPerMonth; }
int getAccountNo() { return AccountNo; }
//setters
void setServChargePerMonth(float servCharge) //note: increasing, not setting
{
ServChargePerMonth += servCharge;
}
void setWithdrawAmt(float Amount)
{
WithdrwAmt = Amount;
}
void setBalance(float blnce)
{
Balance = blnce;
}
void setDepoAmt(float Amount)
{
DepoAmt = Amount;
}
};
class CheckingAccount : public BankAccount
{
public:
void makeWithdrawal(float WithdrwAmt)
{
if ((BankAccount::getBalance() - WithdrwAmt) < 0) //note: float doens't go below 0
setBalance(getBalance() - 15.0); //deducting $15
else
BankAccount::setWithdrawAmt(WithdrwAmt);
BankAccount::makeWithdrawal();
}
};
class SavingsAccount : public BankAccount
{
private:
bool statusVar;
bool status()
{
if (getBalance() < 25.0)
statusVar = false;
else
statusVar = true;
return statusVar;
}
public:
//setter
void setStatus(bool statusVar)
{
statusVar = status();
}
bool getStatus() { return statusVar; }
void makeWithdrawal()
{
if (status()) //check if active
{
cout << "Enter the amount you would like to withdraw today: ";
float WithdrwAmt;
cin >> WithdrwAmt;
CheckingAccount temp;
temp.makeWithdrawal(WithdrwAmt); //perform the reqd. check, as well as call the base ver.
}
else
{
cout << "Your account has deactivated. Please increase "
<< "your balance to reactivate your account.";
}
}
void makeDeposit()
{
cout << "Enter the amount you would like to deposit today: ";
float temp;
cin >> temp;
setDepoAmt(temp); //setting value for amt of deposit
//check previous balance
if (!status()) //if <$25,
{ //reactivate the acc. if depoAmt brings bal to $25
if ((getBalance() + getDepoAmt()) >= 25.0)
setStatus(true);
}
//check
BankAccount::makeDeposit(); //and then call the base ver.
}
};
void createAcc()
{
BankAccount ac;
ofstream writeFile;
writeFile.open("Account.dat", ios::binary | ios::app);
ac.createAcc();
writeFile.write(reinterpret_cast<char *>(&ac), sizeof(BankAccount));
writeFile.close();
}
void makeDepositOrWithdraw(int option)
{
int num;
cout << "\nEnter account number: ";
cin >> num;
int amt;
bool found = false;
BankAccount ac;
SavingsAccount save;
fstream File;
File.open("Account.dat", ios::binary | ios::in | ios::out);
if (!File)
{
cout << "Cannot retrieve database right now. Try again later";
return;
}
while (!File.eof() && found == false)
{
File.read(reinterpret_cast<char *>(&ac), sizeof(BankAccount));
if (ac.getAccountNo() == num)
{
ac.displayAcc();
if (option == 1)
save.makeDeposit();
if (option == 2)
save.makeWithdrawal();
int pos = (-1) * static_cast<int>(sizeof(ac));
File.seekp(pos, ios::cur);
//File.write((char *)&ac, sizeof(BankAccount));
File.write(reinterpret_cast<char *>(&ac), sizeof(BankAccount));
cout << "__________________________________"
<< "\nRecord updated ";
found = true;
}
}
File.close();
if (!found)
cout << "Record not found";
}
void display()
{
int num;
cout << "\nEnter account number: ";
cin >> num;
bool flag = false;
BankAccount ac;
ifstream inFile;
inFile.open("Account.dat", ios::binary);
if (!inFile)
{
cout << "Cannot retrieve database right now. Try again later";
return;
}
cout << "\nBALANCE DETAILS\n";
while (inFile.read(reinterpret_cast<char *>(&ac), sizeof(BankAccount)))
{
if (ac.getAccountNo() == num)
{
ac.displayAcc();
flag = true;
}
}
inFile.close();
if (!flag)
cout << "\nAccount number does not exist";
}
void deleteAcc()
{
int num;
cout << "\nEnter account number: ";
cin >> num;
BankAccount ac;
ifstream inFile;
ofstream outFile;
inFile.open("Account.dat", ios::binary);
if (!inFile)
{
cout << "Cannot retrieve database right now. Try again later";
return;
}
outFile.open("temp.dat", ios::binary);
inFile.seekg(0, ios::beg);
while (inFile.read(reinterpret_cast<char *>(&ac), sizeof(BankAccount)))
{
if (ac.getAccountNo() != num)
{
outFile.write(reinterpret_cast<char *>(&ac), sizeof(BankAccount));
}
}
inFile.close();
outFile.close();
remove("Account.dat");
rename("temp.dat", "Account.dat");
cout << "__________________________________________"
<< "Your account has been closed.";
}
int main()
{
char opt;
int temp;
start:
do
{
system("clear");
cout << "\n1. Create new account"
<< "\n2. Make a deposit"
<< "\n3. Make a withdrawal"
<< "\n4. Balance enquiry"
<< "\n5. Close existing account"
<< "\n6. Exit"
<< "\n\nPlease select your option(1-6)" << endl;
cin >> opt;
system("clear");
switch (opt)
{
case '1':
createAcc();
break;
case '2':
makeDepositOrWithdraw(1);
break;
case '3':
makeDepositOrWithdraw(2);
break;
case '4':
display();
break;
case '5':
deleteAcc();
break;
case '6':
cout << "Thank you for banking with us" << endl;
break;
default:
cout << "\a" << endl;
goto start;
break;
}
cin.ignore();
cin.get();
} while (opt != '6');
}
C++ places restrictions on the kind of objects you can use binary reads and writes on. They are complicated rules but the problem with your BankAccount object is that it has virtual functions and these mean you cannot use binary reads and writes.
Another problem is that you have several different kind of objects but your code reads and writes only BankAccount objects, not CheckingAccount objects or SavingsAccount objects.
So the code as written cannot work.
It's a common beginner mistake. Binary reads and writes are very limited in their functionality but beginners try to read and write all sorts of complex objects and expect it to just work, which it doesn't.
You need to redesign how you do the I/O in your program. I'm not sure what you requirements are but dropping the use of binary I/O seems the simplest way to proceed.
Related
This is all my code I want to sort the records when display all students using option 2 in the main menu
this code returning me the data as it was saved means unsorted.
#include<iostream>
#include<fstream>
#include<iomanip>
#include<vector>
using namespace std;
class student
{
int Idnum;
char Name[25];
char Course[30];
int Result;
public:
void getdata();
void showdata() const;
void show_tabular() const;
int getIDNum() const;
};
void student::getdata()
{
cout << "\nEnter student's ID Number: ";//prints Enter student's ID Number
cin >> Idnum;
cout << "\n\nEnter student's Name: ";//prints Enter student's Name
cin.ignore();//to ignore from the input buffer
cin.getline(Name, 25);
cout << "\nEnter student's Course: ";//prints Enter student's Course
cin >> Course;
cout << "\nEnter student's Result: ";//prints Enter student's Result
cin >> Result;
}
void student::showdata() const
{
cout << "\nID Number: " << Idnum;//prints ID Number
cout << "\nName: " << Name;//prints Name
cout << "\nCourse: " << Course;//prints Course
cout << "\nResult: " << Result;//prints Result
}
void student::show_tabular() const
{
cout << Idnum << setw(6) << " " << Name << setw(20) << Course << setw(20) << Result << setw(4) << endl;
}
int student::getIDNum() const
{
return Idnum;
}
void SaveStudent();
void displayAll();
void Searchdisplay(int);
void modifyStudent(int);
void deleteStudent(int);
void DisplayResult();
This is the code for creating a student.dat file if it does not exist here and if will exist then write a new student record but this will not sort the records as I want.
void write_student()//to create students record
{
student st;
ofstream outFile;
ifstream inFile;
outFile.open("student.dat", ios::binary | ios::app);//opens file student.dat
st.getdata();
//cout << st.getIDNum();
if (inFile.seekg(reinterpret_cast<char *> (&st)))
{
}
outFile.write(reinterpret_cast<char *> (&st), sizeof(student));//writes the file
outFile.close();//closes the file
cout << "\n\nStudent record Has Been Created ";
cin.ignore();
cin.get();
}
This is the place where I am showing my student's records but this will show unsorted records and I want it in a sorted way means ascending order by roll no of students.
void display_all()//to display the student record
{
student st;
ifstream inFile;
inFile.open("student.dat", ios::binary);//opens file student.dat
if (!inFile)
{
cout << "File could not be open !! Press any Key...";
cin.ignore();//to ignore from the input buffer
cin.get();//to access the char
return;
}
cout << "\n\n\n\t\tDISPLAY ALL RECORD !!!\n\n";
while (inFile.read(reinterpret_cast<char *> (&st), sizeof(st)))
{
st.showdata(); //function to show data on screen
cout << "\n\n====================================\n";
}
inFile.close();//closes the file
cin.ignore();
cin.get();
}
void display_sp(int n)//to search for student record
{
student st;
ifstream inFile;
inFile.open("student.dat", ios::binary);//opens file student.dat
if (!inFile)
{
cout << "File could not be open !! Press any Key...";
cin.ignore();
cin.get();
return;
}
bool flag = false;//for false condition
while (inFile.read(reinterpret_cast<char *> (&st), sizeof(student)))
{
if (st.getIDNum() == n)
{
st.showdata();
flag = true;
}
}
inFile.close();//closes the file
if (flag == false)
cout << "\n\nrecord not exist";//prints record not exist
cin.ignore();
cin.get();
}
void modify_student(int n)//to modify the record
{
bool found = false;//for false condition
student st;
fstream File;
File.open("student.dat", ios::binary | ios::in | ios::out);//opens the file student.dat
if (!File)
{
cout << "File could not be open !! Press any Key...";
cin.ignore();
cin.get();
return;
}
while (!File.eof() && found == false)
{
File.read(reinterpret_cast<char *> (&st), sizeof(student));//reads the file
if (st.getIDNum() == n)
{
st.showdata();
cout << "\n\nPlease Enter The New Details of student" << endl;
st.getdata();
int pos = (-1)*static_cast<int>(sizeof(st));
File.seekp(pos, ios::cur);
File.write(reinterpret_cast<char *> (&st), sizeof(student));
cout << "\n\n\t Record Updated";
found = true;
}
}
File.close();//closes the file
if (found == false)
cout << "\n\n Record Not Found ";
cin.ignore();
cin.get();
}
void delete_student(int n)//to delete the student record
{
student st;
ifstream inFile;
inFile.open("student.dat", ios::binary);//opens the student.dat file
if (!inFile)
{
cout << "File could not be open !! Press any Key...";
cin.ignore();
cin.get();
return;
}
ofstream outFile;
outFile.open("Temp.dat", ios::out);//to open another file
inFile.seekg(0, ios::beg);
while (inFile.read(reinterpret_cast<char *> (&st), sizeof(student)))
{
if (st.getIDNum() != n)
{
outFile.write(reinterpret_cast<char *> (&st), sizeof(student));
}
}
outFile.close();//to open another file
inFile.close();
remove("student.dat");
rename("Temp.dat", "student.dat");
cout << "\n\n\tRecord Deleted ..";
cin.ignore();
cin.get();
}
int main()
{
char ch;
int num;
cout.setf(ios::fixed | ios::showpoint);
cout << setprecision(2);
do
{
system("cls");
cout << "\t===================================";
cout << "\n\n\t1. CREATE STUDENT RECORD";
cout << "\n\n\t2. DISPLAY ALL STUDENTS RECORDS";
cout << "\n\n\t3. SEARCH STUDENT RECORD ";
cout << "\n\n\t4. MODIFY STUDENT RECORD";
cout << "\n\n\t5. DELETE STUDENT RECORD";
cout << "\n\n\t6. EXIT";
cout << "\n\n\t===================================";
cout << "\n\n\tPlease Enter Your Choice (1-6): ";
cin >> ch;
system("cls");
switch (ch)//uses switch casee
{
case '1': write_student(); break;
case '2': display_all(); break;
case '3': cout << "\n\n\tPlease Enter Student's ID number: "; cin >> num;
display_sp(num); break;
case '4': cout << "\n\n\tPlease Enter Student's ID number: "; cin >> num;
modify_student(num); break;
case '5': cout << "\n\n\tPlease Enter Student's ID number: "; cin >> num;
delete_student(num); break;
case '6': exit(0);;
default: cout << "\a";
}
} while (ch != '6');
return 0;
}
The main difficulty with showing students in sorted order is that your program works by having every function read a file and operate on each student record sequentially. Sorting can only happen when you have all of the data loaded into your program. In order to display a sorted list of students, you need to load all of the student records into your program and put them all in the same container. A std::vector<student> is the simplest container to work with here.
So, I think the overall flow of your program should work like this:
Read the entirety of student.dat and put all student information found there in a container like std::vector<student>.
Sort the container.
Let the user manipulate the records (create, read, update, delete) by modifying the members of the std::vector<student>.
When the user wants to exit, write the contents of the std::vector<student> back to the file students.dat (possibly with an option to quit without saving).
In the next section, suggestions 1 and 2 answer your question while suggestion 3 tells how the rest of your program will need to be changed to work with the first two suggestions.
Some suggestions to do this:
Make it easier to load a student from a file.
Create a method for the student class that takes a std::ifstream& as an argument. That way, after you open a file, you can load all of the student data like this:
int main()
{
ifstream inFile("student.dat");
std::vector<student> all_students;
while(inFile)
{
student st;
st.getData(inFile);
all_students.push_back(st);
}
// continue with program
}
This method will be very similar to the current student::getData() method, but it will skip the text prompts. I also find this way much easier to understand than your reinterpret_cast code that makes me worry about what it actually does. Is student.dat human readable in your current code?
Create a comparison function bool operator<(const student& A, const student& B) for sorting.
This function should return true if the A student should be sorted before B student and false otherwise. Once this method is created, then you can call std::sort(all_students.begin(), all_students.end()) to sort the student list by the criteria defined in that comparison function. The std::sort() function will need to be called after every modification to the student list.
All functions that manipulate student data should get passed the all_students data
It is much easier to work with the student data directly through purpose-written methods rather than doing complicated manipulations of filestream data. For example, if you passed std::vector<student>& to the modify_student() function, it would look like this:
void modify_student(std::vector<student>& all_students, int n)//to modify the record
{
for (auto& st : all_students)
{
if (st.getIDNum() == n)
{
st.showdata();
cout << "\n\nPlease Enter The New Details of student" << endl;
st.getdata();
return;
}
}
cout << "\n\n Record Not Found ";
}
If you are not working in C++11 or later, this is equivalent:
void modify_student(std::vector<student>& all_students, int n)//to modify the record
{
for (size_t i = 0; i < all_students.size(); ++i)
{
student& st = all_students[i];
if (st.getIDNum() == n)
{
st.showdata();
cout << "\n\nPlease Enter The New Details of student" << endl;
st.getdata();
return;
}
}
cout << "\n\n Record Not Found ";
}
This is much simpler since you don't have file-traversal and user input/output hiding the actual logic of the function.
If a function is only displaying data like display_all(), then you should pass the student list as const std::vector<student>& all_students.
There's much more to be done to improve this program, but I think these suggestions should get you started thinking in a more organized way.
I created my program in Visual Studio, it works perfectly the input / output etc. are all correct. When I run it in AWS Cloud 9 or Mirmir I get the same error message, What does this mean? How should I modify it to work in AWS? I thought C++ codes work in all IDE which supports C++. The errors are:
In constructor ‘Departments::Departments(int, char*, char*)’:
error: ‘strcpy_s’ was not declared in this scope
strcpy_s(Departmentname, nameOfDepartment);
^
In constructor ‘Employee::Employee(int, char*, double, double, int)’:
error: ‘strcpy_s’ was not declared in this scope
strcpy_s(emploeename, nameOfTheEmployee);
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;
const int SizeForString = 100;
char deptartmentRecordFileName[100] = "departments.dat ";
char employeeRecordFileName[100] = "employees.dat";
struct Departments {
int DepartmentID;
char Departmentname[SizeForString];
char DepartmentHeadName[SizeForString];
Departments()
{
}
Departments(int idOfTheDepartment, char nameOfDepartment[], char headNameOfDepartment[])
{
DepartmentID = idOfTheDepartment;
strcpy_s(Departmentname, nameOfDepartment);
strcpy_s(DepartmentHeadName, headNameOfDepartment);
}
};
struct Employee {
int employeeID;
char emploeename[SizeForString];
double employeesalary;
double employeeage;
int employeeDepartmentID;
Employee()
{
}
Employee(int idOfTheEmployee, char nameOfTheEmployee[], double salaryOfTheEmployee, double ageOfTheEmployee, int departmentId)
{
employeeID = idOfTheEmployee;
strcpy_s(emploeename, nameOfTheEmployee);
employeesalary = salaryOfTheEmployee;
employeeage = ageOfTheEmployee;
employeeDepartmentID = departmentId;
}
};
bool DepartmentIdCheck (int id)
{
Departments temp;
ifstream myfile1(deptartmentRecordFileName, ios::in | ios::binary | ios::app);
if (!myfile1)
{
cout << "Error To Open File.\n";
return false;
}
while (myfile1.read((char*)&temp, sizeof(Departments)))
{
if (temp.DepartmentID == id)
{
myfile1.close();
return true;
}
}
myfile1.close();
return false;
}
bool checkIDEmplyee (int id)
{
Employee temp;
ifstream myfile1(employeeRecordFileName, ios::in | ios::binary | ios::app);
if (!myfile1)
{
cout << "Error To Open File.\n";
return false;
}
while (myfile1.read((char*)&temp, sizeof(Employee)))
{
if (temp.employeeID == id)
{
myfile1.close();
return true;
}
}
myfile1.close();
return false;
}
void writeDepartmentData(Departments temp)
{
ofstream myfile1(deptartmentRecordFileName, ios::out | ios::binary | ios::app);
if (!myfile1)
{
cout << "Error To Open File.\n";
return;
}
myfile1.write((char*)&temp, sizeof(Departments));
myfile1.close();;
}
void writeEmployeeData(Employee temp)
{
ofstream myfile1(employeeRecordFileName, ios::out | ios::binary | ios::app);
if (!myfile1)
{
cout << "Error To Open File.\n";
return;
}
myfile1.write((char*)&temp, sizeof(Employee));
myfile1.close();
}
void createReport()
{
double totalSalary = 0;
Departments depTemp;
ifstream myfile1(deptartmentRecordFileName, ios::in | ios::binary | ios::app);
if (!myfile1)
{
cout << "Error To Open File.\n";
return;
}
while (myfile1.read((char*)&depTemp, sizeof(Departments)))
{
Employee empTemp;
ifstream myfile2(employeeRecordFileName, ios::in | ios::binary | ios::app);
while (myfile2.read((char*)&empTemp, sizeof(Employee)))
{
if (!myfile1)
{
cout << "Error To Open File.\n";
return;
}
if (depTemp.DepartmentID == empTemp.employeeDepartmentID)
{
totalSalary += empTemp.employeesalary;
}
}
cout << "Dept : " << depTemp.Departmentname << endl;
cout << "Total Salary : $" << totalSalary << endl << endl;
myfile2.close();
totalSalary = 0;
}
myfile1.close();
}
int main()
{
int choice = 0;
while (choice != 4)
{
cout << "\nHuman Resources Menu";
cout << "\n1. Create Department"
"\n2. Create Employee"
"\n3. Display Salary Report"
"\n4. -- Quit -- " << endl;
cout << "Please make a selection : ";
cin >> choice;
if (choice == 1)
{
int deptIdInput;
char nameDeptInput[SizeForString];
char headNameInput[SizeForString];
cout << "Please Enter Department Details:" << endl;
cout << "Department ID : ";
cin >> deptIdInput;
bool IdExit = DepartmentIdCheck (deptIdInput);
if (IdExit)
{
cout << "Value must be unique!" << endl;
continue;
}
cout << "Department Name : ";
cin >> nameDeptInput, SizeForString;
cout << "Head of Department : ";
cin >> headNameInput;
Departments d(deptIdInput, nameDeptInput, headNameInput);
writeDepartmentData(d);
}
else if (choice == 2)
{
int idEmploy;
char nameEmploy[SizeForString];
double salaryEmploy;
double ageEmploy;
int departmentIdForEmploy;
cout << "Please Enter Employee Details:" << endl;
cout << "Employee ID : ";
cin >> idEmploy;
bool IdExit = checkIDEmplyee (idEmploy);
if (IdExit)
{
cout << "Value must be unique !" << endl;
continue;
}
cout << "Employee Name : ";
cin >> nameEmploy;
cin.ignore();
cout << "Salary: $";
cin >> salaryEmploy;
cout << "Age : ";
cin >> ageEmploy;
cout << "Department ID : ";
cin >> departmentIdForEmploy;
bool foundId = DepartmentIdCheck (departmentIdForEmploy);
while (!foundId)
{
cout << "Please enter a valid department ID : ";
cin >> departmentIdForEmploy;
foundId = DepartmentIdCheck (departmentIdForEmploy);
}
Employee e(idEmploy, nameEmploy, salaryEmploy, ageEmploy, departmentIdForEmploy);
writeEmployeeData(e);
}
else if (choice == 3)
{
createReport();
}
else if (choice != 4)
{
cout << "Please enter a valid choice" << endl;
}
}
}
Your Visual Studio IDE may have loaded in libraries for you that your other IDEs do not. It looks like strcpy is part of the <cstring> library. You will need to #include <cstring> to use it.
Visual Studio runs on Windows while Cloud9 runs on linux. They use different compilers with different standard libraries.
struct employee
{
string empid;
string lastn;
string firstn;
float hours;
float payrate;
float taxrate;
};
const int SIZE = 100;
int main()
{
employee eCount[SIZE];
string empF;
int count, option1;
fstream inFile;
inFile.open("personnel1.dat", ios::in | ios::out);
count = 0;
cout << "Enter an Employee ID to Change Values (i.e Cv299): ";
cin >> empF;
cin.ignore();
while (!inFile.eof())
{
count += 1;
inFile >> eCount[count].empid >> eCount[count].lastn >> eCount[count].firstn >> eCount[count].hours >> eCount[count].payrate >> eCount[count].taxrate;
if (empF == eCount[count].empid)
{
do
{
cout << "1. Change Employee's ID (" << eCount[count].empid << ")\n";
cout << "2. Change Employee's Last Name (" << eCount[count].lastn << ")\n";
cout << "3. Change Employee's First Name (" << eCount[count].firstn << ")\n";
cout << "4. Change Employee's Hours Worked (" << eCount[count].hours << ")\n";
cout << "5. Change Employee's Pay Rate (" << eCount[count].payrate << ")\n";
cout << "6. Change Employee's Tax Rate (" << eCount[count].taxrate << ")\n";
cout << "7. Quit!\n\n";
cout << "Enter 1 - 7: ";
cin >> option1;
cin.ignore();
switch (option1)
{
case 1:
{
cout << "What would you like to change the Employee ID to?: ";
getline(cin, eCount[count].empid);
break;
}
case 2:
{
cout << "What would you like to change the Employee's Last Name to?: ";
getline(cin, eCount[count].lastn);
break;
}
case 3:
{
cout << "What would you like to change the Employee's First Name to?: ";
getline(cin, eCount[count].firstn);
break;
}
case 4:
{
cout << "What would you like to change the Employee's Hours Worked to?: ";
cin >> eCount[count].hours;
cin.ignore();
break;
}
case 5:
{
cout << "What would you like to change the Employee's Pay Rate to?: ";
cin >> eCount[count].payrate;
cin.ignore();
break;
}
case 6:
{
cout << "What would you like to change the Employee's Tax Rate to?: ";
cin >> eCount[count].taxrate;
cin.ignore();
break;
}
default:
break;
}
} while (option1 != 7);
}
}
inFile << eCount[count].empid << eCount[count].lastn << eCount[count].firstn << eCount[count].hours << eCount[count].payrate << eCount[count].taxrate;
inFile.close();
}
The program is supposed to read the file and also allow the user to write to it. After inputting a valid employee ID it pops up the menu allowing the user to enter what they want to change. After inputting those changes and closing the file, it doesn't update the file. It still shows the same values from before.
You can do some thing like,
This code copies Line by line from old file to a tempfile. When you find the line which you want to update, change it with your line and copy it to the tempfile. Then finally copy all data from tempfile to file and delete tempfile
#include<iostream>
#include<fstream>
#include<stdlib.h>
using std::cout;
using std::endl;
using std::cin;
using std::ios;
class Employee
{
public:
std::string empname;
std::string empid;
};
int main()
{
std::fstream file("emp"),tempfile("tempemp");
Employee emp;
std::string id;
if(!file.is_open()||!tempfile.is_open())
{
file.open("emp",ios::out); //create a file
tempfile.open("tempemp",ios::out); //create a file
if(!file.is_open()||!tempfile.is_open())
{
cout<<"File Error";
exit(1);
}
else
{
file.close();
tempfile.close();
file.open("emp"); // open file for both read and write
tempfile.open("emp"); // open file for both read and write
if(!file.is_open()||!tempfile.is_open())
{
cout<<"File Error";
exit(1);
}
}
}
for(int i=0;i<3;i++) // taking 3 employee name and id
{
cout<<"Enter Name and id:"<<endl;
cin>>emp.empname;
cin>>emp.empid;
file.write((char*)&emp,sizeof emp);
}
cout<<"Contents:"<<endl; //printing contents
file.seekg(0,ios::beg); //move get pointer to beginning
while(file.peek()!=EOF)
{
file.read((char*)&emp,sizeof emp);
cout<<emp.empname<<endl;
cout<<emp.empid<<endl;
}
file.clear(); //reset file
cout<<"Enter Id to Modify:"<<endl;
cin>>id; // which id to modify
file.seekg(0,ios::beg); //move get pointer to beg
tempfile.seekp(0,ios::beg); //move get pointer to beg
while(file.peek()!=EOF)
{
file.read((char*)&emp,sizeof emp);
if(emp.empid==id) //if emp id in file equal to id then
{ //save to tempfile the name and id of user entered
cout<<"Enter New name and id:"<<endl;
cin>>emp.empname;
cin>>emp.empid;
tempfile.write((char*)&emp,sizeof emp);
}
else // if not equal save the content in file to tempfile
{
tempfile.write((char*)&emp,sizeof emp);
}
}
file.clear(); //reset file
tempfile.seekg(0,ios::beg); //move get pointer pos to beg
file.seekp(0,ios::beg); //move put pointer pos to beg
while(tempfile.peek()!=EOF)
{
tempfile.read((char*)&emp,sizeof emp); //copy contents of tempfile to file
file.write((char*)&emp,sizeof emp);
}
file.clear(); //reset file
tempfile.close(); //close file
remove("tempemp"); //remove tempemp pointed by tempfile
cout<<"Modified Contents:"<<endl; //print modified contents
file.seekg(0,ios::beg); //move get pointer pos to beg
while(file.peek()!=EOF)
{
file.read((char*)&emp,sizeof emp);
cout<<emp.empname<<endl;
cout<<emp.empid<<endl;
}
file.close(); //close file
return 0;
}
i am used name and id only for simplicity
(OR)
you can use like this also,But this code did not use tempfile. it replaces the new content directly in the file.
#include<iostream>
#include<fstream>
#include<stdlib.h>
using std::cout;
using std::endl;
using std::cin;
using std::ios;
class Employee
{
public:
std::string empname;
std::string empid;
};
int main()
{
std::fstream file("emp");
Employee emp;
std::string id;
std::fstream::pos_type pos=0; //for position
if(!file.is_open())
{
file.open("emp",ios::out);
if(!file.is_open())
{
cout<<"File Error";
exit(1);
}
else
{
file.close();
file.open("emp");
if(!file.is_open())
{
cout<<"File Error";
exit(1);
}
}
}
for(int i=0;i<3;i++)
{
cout<<"Enter Name and id:"<<endl;
cin>>emp.empname;
cin>>emp.empid;
file.write((char*)&emp,sizeof emp);
}
cout<<"Contents:"<<endl;
file.seekg(0,ios::beg);
while(file.peek()!=EOF)
{
file.read((char*)&emp,sizeof emp);
cout<<emp.empname<<endl;
cout<<emp.empid<<endl;
}
file.clear();
cout<<"Enter Id to Modify:"<<endl;
cin>>id;
file.seekg(0,ios::beg);
file.seekp(0,ios::beg);
pos=file.tellp(); //get init pos
while(file.peek()!=EOF)
{
pos=file.tellp(); //update pos
file.read((char*)&emp,sizeof emp);
if(emp.empid==id)
{
cout<<"Enter New name and id:"<<endl;
cin>>emp.empname;
cin>>emp.empid;
file.seekp(pos); // change pos
file.write((char*)&emp,sizeof emp); //save modified content
}
}
file.clear();
cout<<"Modified Contents:"<<endl;
file.seekg(0,ios::beg);
while(file.peek()!=EOF)
{
file.read((char*)&emp,sizeof emp);
cout<<emp.empname<<endl;
cout<<emp.empid<<endl;
}
file.close();
return 0;
}
In file streams only tellg changes tellp but it not for other streams for more info see this
are "seekp" & "seekg" interchangeable?
I have wriiten a code to add , delete and dispaly a record of employees consisting of employee ID ,name,age and location.
But I am unable to code the delete function
My code is as follows:
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
class Document
{
public:
int Add();
void Delete();
void Display();
int No_of_lines();
int empno();
private:
fstream document;
fstream newdocument;
string data;
int age;
int emp_id;
int idtodelete;
char name[100],loc[100];
};
int Document::No_of_lines()
{
int number = 0;
document.open("document.txt");
while (getline(document, data))
{
++number;
}
return number;
}
int Document::Add()
{
Document d1;
document.open ( "document.txt",ios::app);
int x = d1.No_of_lines();
int emp_id = ++x;
cout << "The employee ID is: " << emp_id;
document <<emp_id;
cout<< "\n Ënter Name:" ;
cin>>name;
document <<"\t Name:"<< name;
cout<<"Enter Age:";
cin>> age;
document << "\t Age:"<< age;
cout<< "Enter location:";
cin>> loc;
document << "\t Location:"<< loc;
document << "\n";
document.close();
return 0;
}
void Document::Delete()
{
Document d2;
d2.Display();
int num;
char line[1000];
document.open("document.txt");
newdocument.open("newdocument.txt");
cout << "Enter the ID to delete \n";
cin >> idtodelete;
while (document.good())
{
const int maxchar = 1000;
const int maxtokens = 10;
char* token[maxtokens] = {};
char split[maxchar];
document.getline(split, maxchar);
int n = 0;
token[0] = strtok(split, " ");
istringstream(token[0]) >> num;
if (num != idtodelete)
{
document >> emp_id >> name >> age >> loc;
newdocument << emp_id<< name<< age<< loc;
}
else
{
}
}
document.close();
newdocument.close();
remove("document.txt");
rename("newdocument.txt", "document.txt");
}
void Document::Display()
{
document.open("document.txt");
while (!document.eof())
{
getline(document,data);
cout<<data<<endl;
}
document.close();
}
int main()
{
Document d;
char ans;
int ch;
do
{
system ( "cls");
cout<< "Enter your choice \n";
cout << "\t1. Add Data \n " << "\t2. Delete Data \n" << "\t3. Display Data \n";
cout<< "\t4. Exit\n";
cout<< " Enter Choice \n ";
cin >> ch;
switch(ch)
{
case 1:
cout << " Adding Data : \n";
d.Add();
break;
case 2:
//cout << "Deleting data : \n";
d.Delete();
break;
case 3:
cout << "Displaying data : \n";
d.Display();
break;
case 4:
cout << "Exit";
break;
default :
cout << "Invalid Input \n";
break;
}
cout<< " click y to quit or any other key to continue " ;
cin>>ans;
}
while (ans != 'y');
return 0;
}
The simple way is to remove by employee ID. You just ask for the employee ID, to know what employee to remove.
Then, you cannot remove lines in the middle of a sequential file, so you just
rename the file as document.back
create a new document.txt
read document.back and copy all employees to document.txt except the one you want to delete
close both files
remove document.back
That's all ... except for the usual test for IO errors, backup file existing, and so on...
I tested your code. First, you forgot to close document in method int Document::No_of_lines(). Next on my MSVC2008, I have to explicitely call document.clear() after reaching end of file. You also do not test document immediately after a getline, meaning that you execute the code after a bad read.
I removed newdocument from Document class, because IMHO it is useless. Here is a possible implementation of Delete:
void Document::Delete()
{
Document d2;
Display();
int num;
document.open("document.txt");
document.clear();
d2.document.open("newdocument.txt", ios::out | ios::trunc);
cout << "Enter the ID to delete \n";
cin >> idtodelete;
while (document.good())
{
getline(document, data);
if (document) {
int n = 0;
istringstream(data) >> num;
if (num != idtodelete)
{
d2.document << data << endl;
}
}
}
document.close();
d2.document.close();
remove("document.txt");
rename("newdocument.txt", "document.txt");
}
For some reason my bank script isn't working. More specifically, the search() does not work. I kind of understand why it doesn't, probably because of if(obj.returnId() == n), but I have no clue how to fix it. When I search an account, it will only allow me to find the last account made, not any of the previous ones. Here is my code:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <string.h>
#include <fstream>
#include <Windows.h>
#include <conio.h>
using namespace std;
bool loop = true;
class account
{
int id;
char name[40];
char password[40];
public:
void getData()
{
cout << "\nEnter your name: ";
cin >> name;
cout << "\nEnter ID: ";
cin >> id;
cout << "\Enter pass: ";
cin >> password;
}
void showData()
{
cout << "\nName: ";
puts(name);
cout << "\nID: " << id;
cout << "\n";
}
int returnId()
{
return id;
}
};
void createAccount()
{
account obj;
ofstream fileCreate;
fileCreate.open("accounts.dat", ios::binary|ios::app);
obj.getData();
fileCreate.write((char*)&obj,sizeof(obj));
fileCreate.close();
}
void display()
{
account obj;
ifstream fileRead;
fileRead.open("accounts.dat", ios::binary);
while(fileRead.read((char*)&obj, sizeof(obj)))
{
obj.showData();
}
fileRead.close();
}
void search(int n)
{
account obj;
ifstream fileRead;
fileRead.open("accounts.dat", ios::binary);
while(fileRead.read((char *) &obj, sizeof(obj)) );
{
fileRead.seekg(0,ios::beg);
if(obj.returnId() == n)
{
obj.showData();
}
else {
cout << "\nUser not foud!\n";
}
}
fileRead.close();
}
void main()
{
cout << "Welcome to the Bank.\n\n";
while (loop==true)
{
char choice[10];
cout << "Please select an option:\n";
cout << "------------------------------------------------\n";
cout << "(a)Log into an account\n(b)Create an account\n(s)Search an account\n(e)Exit\n";
cout << "------------------------------------------------\n";
cout << "Choice: ";
cin >> choice;
choice[0] = tolower(choice[0]);
cout << "\n------------------------------------------------\n\n";
switch (choice[0])
{
case 'a':
display();
break;
case 's':
int n;
cout << "Enter the ID of the account: ";
cin >> n;
search(n);
break;
case 'b':
createAccount();
break;
case 'e':
loop = false;
break;
default:
system("CLS");
cout << "The option \"" << choice[0] << "\" is invalid.\n\n\n\n";
break;
}
};
cout << "\n\n\n";
cout << "Click anything to exit.";
getch();
}
Your problem is the semicolon at the end of this line:
while(fileRead.read((char *) &obj, sizeof(obj)) );
That makes this loop have an empty body. So you basically read the whole file and throw away the results, except for the last entry.
get rid of this also:
fileRead.seekg(0,ios::beg);
I don't know why you need that, it would only make you read the first entry over and over.
The other error is that you should only say 'User not found' when you've tested all the accounts and they all failed. Your loop (when you've removed the semi-colon) is saying 'User not found' after every failed test.
You probably don't find the entry you are looking for because each time you have read an entry from the file, you reset the position to the beginning. This means that your loop will run forever, reading the same entry over and over again and never finding the entry you search for.
the seek might be the problem:
while(fileRead.read((char *) &obj, sizeof(obj)) ) //;
{
// seek to start?
//fileRead.seekg(0,ios::beg);
...
}
have a look at http://www.boost.org/doc/libs/1_51_0/libs/serialization/doc/index.html
aside, use
cout << "text" << endl;
for platform-agnostic newlines.