Why does this file always contain an extra Fraction structure? If a user enters option 3 to view all fractions when the program just starts (the file should be empty), 0/0 is printed out. If a user selects option one and enters a fraction 1/1, and then selects option 3, two fractions are printed out 1/1 1/1.
Note: to run this you will need to create an empty .dat file called "fractions.dat"
I really appreciate your help!
#include <iostream>
#include <fstream>
using namespace std;
struct Fraction
{
int num, den;
};
int search(fstream& file, Fraction* f);
int menu();
void proccessChoice(int i);
Fraction* readFrac();
Fraction* fracs[100];
int index;
string fileName = "fractions.dat";
fstream file(fileName, ios::in | ios::out | ios::binary | ios::trunc);
//structure called Fraction with num and den as its only integer members
int main()
{
if (!file)
{
cout << "Error opening file. Program aborting.\n";
system("pause");
exit(1);
}
int choice;
do
{
choice = menu();
proccessChoice(choice);
} while(choice != 4);
system("pause");
return 0;
}
int menu()
{
int c;
cout << "1.Enter new fraction" << endl;
cout << "2.Display/update a fraction" << endl;
cout << "3.Display all fractions" << endl;
cout << "4.Quit" << endl;
cin >> c;
return c;
}
void proccessChoice(int i)
{
switch(i)
{
case 1:
{
cout << "Enter a fraction to add: ";
fracs[index] = readFrac();
file.seekp(0, ios::end);
file.write(reinterpret_cast<char*>(fracs[index]), sizeof(Fraction));
/*cout << fracs[index]->num << "/" << fracs[index]->den ;*/
index++;
}
break;
case 2:
{
cout << "Enter fraction to view/update: ";
Fraction* fToFind = readFrac();
int i = search(file, fToFind);
if (i == -1)
{
cout << "Fraction not found." << endl;
}
else
{
char r;
cout << fToFind->num << "/" << fToFind->den << " found at index " << i << ". Update? [y/n]";
cin >> r;
if(r == 'y' || r == 'Y')
{
cout << "Enter a new fraction: ";
Fraction* fToWrite = readFrac();
file.seekp(sizeof(Fraction) * (i));
file.write(reinterpret_cast<char*>(fToWrite), sizeof(Fraction));
}
}
cout << i << endl;
cout << "Case 2" << endl;
}
break;
case 3:
{
Fraction* cur = new Fraction();
//int pos = -1;
if (!file)
{
cout << "Error opening file. Program aborting.\n";
system("pause");
exit(1);
}
file.seekg(0, ios::beg);
while(!file.eof())
{
file.read(reinterpret_cast<char *>(cur), sizeof(Fraction));
cout << cur->num << "/" << cur->den << endl;
}
cout << "Case 3" << endl;
}
break;
}
}
int search(fstream& file, Fraction* f)
{
Fraction* cur = new Fraction();
int pos = -1;
if (!file)
{
cout << "Error opening file. Program aborting.\n";
system("pause");
exit(1);
}
file.seekg(0, ios::beg);
while(!file.eof())
{
file.read(reinterpret_cast<char *>(cur), sizeof(Fraction));
if((cur->num == f->num) && (cur->den == f->den))
{
cout << "\nFrac found!" << cur->num << "/" << cur->den<<endl;
pos = file.tellg()/sizeof(Fraction) - 1;
return pos;
}
}
return pos;
}
Fraction* readFrac()
{
Fraction* f = new Fraction();
char slash;
cin >> f->num >> slash >> f->den;
return f;
}
Attempted solution 1: works for the first attempt of the user to view all fractions but on the second attempt the file is not found.
case 3:
{
Fraction* cur = new Fraction();
//int pos = -1;
if (!file)
{
cout << "Error opening file. Program aborting.\n";
system("pause");
exit(1);
}
file.seekg(0, ios::beg);
while(!file.eof())
{
if(file.read(reinterpret_cast<char *>(cur), sizeof(Fraction)).gcount()== sizeof(Fraction))
{
cout << cur->num << "/" << cur->den << endl;
}
}
cout << "Case 3" << endl;
}
break;
}
Because you didn't yet reach the end of the file!
while(!file.eof())
You opened the empty file, however, note that the read cursor is currently at position 0. As long as you didn't attempt to read data file.eof() will be false, as the end of file hasn't been reached yet by the cursor.
You'll need to check whether you were actually able to extract the Fraction:
if(
file.read(reinterpret_cast<char *>(cur), sizeof(Fraction)).gcount()
== sizeof(Fraction)
){
// Fraction has been extracted
}
else
// either eof() or some other error.
Note that this gets much simpler if you provide a custom operator for this:
std::istream& operator>>(std:istream& in, Fraction& f){
return in.read(reinterpret_cast<char *>(&f), sizeof(Fraction));
}
// ....
while(file >> *cur){
// ... your code.
}
Related
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.
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.
Is this correct?
Here Update is member function of Product class.
I am using this pointer(pointing to calling product object) to read objects stored in file over and over.
file.read((char *)this, sizeof(product));
Here if the class(see the update member function):
class product
{
int product_num;
string product_name;
int quantity;
float sell_p;
float buy_p;
int gst;
float total;
float profit;
public:
void calculate()
{
this->total = this->quantity * (this->sell_p);
this->profit = this->total - (this->buy_p * this->quantity) * (1 + this->gst / 100);
}
product()
{
product_num = 0;
product_name = "\0";
}
product(int p_num, string name, int quantity, float sell_p, float buy_p, int gst)
{
this->product_num = p_num;
this->product_name = name;
this->quantity = quantity;
this->sell_p = sell_p;
this->buy_p = buy_p;
this->gst = gst;
calculate();
}
void get_data()
{
cout << "Enter Serial Number: ";
cin >> this->product_num;
cout << "Enter Product Name(MAX LENGTH: 20): ";
cin>>this->product_name;
cout << "Enter Quantity: ";
cin >> this->quantity;
cout << "Enter Buying Price: ";
cin >> this->buy_p;
cout << "Enter GST: ";
cin >> this->gst;
cout << "Enter Selling Price: (Selling Price should be greater than " << (this->buy_p + (this->gst / 100) * this->buy_p) << " to turn profit)";
cin >> this->sell_p;
calculate();
}
void show_product()
{
cout << "Serial: " << this->product_num
<< "\nName: " << this->product_name
<< "\nQuantity: " << this->quantity
<< "\nSelling Price: " << this->sell_p
<< "\nBuying Price: " << this->buy_p
<< "\nGST: " << this->gst << endl;
}
bool remove_product(int x)
{
if (x > this->quantity)
return false;
this->quantity -= x;
return true;
}
int getSerialNumber()
{
return this->product_num;
}
string getName()
{
return this->product_name;
}
int getQuantity()
{
return this->quantity;
}
int getGST()
{
return this->gst;
}
float getTotal()
{
return this->total;
}
float getProfit()
{
return this->profit;
}
float getSellPrice()
{
return this->sell_p;
}
float getBuyPrice()
{
return this->buy_p;
}
bool isValid()
{
if (product_num == 0 || product_name == "\0")
return false;
return true;
}
void save()
{
ofstream fout;
fout.open("product.dat", ios::binary | ios::app);
if (!fout)
{
cout << "Failed To Open File!!\nExiting..";
exit(0);
}
else
{
fout.write((char *)this, sizeof(product));
}
fout.close();
}
void update()
{
int s_num = this->product_num;
fstream file;
file.open("product.dat", ios::binary | ios::ate | ios::in | ios::out);
if (!file)
{
cout << "Failed to open file!!!\nExiting...." << endl;
exit(0);
}
else
{
file.seekg(0);
file.read((char *)this, sizeof(product));
while (!file.eof())
{
if (s_num == this->product_num)
{
cout << "Product Detail: ";
this->show_product();
cout << "Enter the Values: " << endl;
cout << "Note: IF DONT WISH TO CHANGE KINDLY ENTER SAME VALUE.";
this->get_data();
file.seekp(-(sizeof(product)),ios::cur);
file.write((char *)this, sizeof(product));
break;
}
file.read((char *)this, sizeof(product));
}
}
file.close();
}
void remove_it()
{
int s_num = this->product_num;
ofstream fout;
ifstream fin;
fin.open("product.dat", ios::in | ios::binary);
if (!fin)
{
cout << "Failed to open file!!\nExiting...";
exit(0);
}
else
{
fout.open("temp.dat", ios::binary | ios::out);
fin.read((char *)this, sizeof(product));
while (!fin.eof())
{
if (!(s_num == this->product_num))
{
fout.write((char *)this, sizeof(product));
}
fin.read((char *)this, sizeof(product));
}
fin.close();
fout.close();
if(remove("product.dat") == 0)
cout<<"Sucessfully Deleted file\n";
else
cout<<"File Removal Failed\n";
if(rename("temp.dat", "product.dat") == 0)
cout<<"Successfully Renamed\n";
else
cout<<"Failed to Rename\n";
}
}
};
How do I return the location of an item in a .dat file?
in the search() function I attempting to find an item in the fractions.dat file and return it to the user. However the function always returns -2 (the value that the variable being returned was initialized to originally).
The if statement executes, but it appears that file.read(...) isn't setting cur to anything.
#include <iostream>
#include <fstream>
using namespace std;
struct Fraction
{
int num, den;
};
int search(fstream& file, Fraction* f);
int menu();
void proccessChoice(int i);
Fraction* readFrac();
Fraction* fracs[100];
int index;
string fileName = "fractions.dat";
fstream file(fileName, ios::in | ios::out | ios::binary);
int main()
{
if (!file)
{
cout << "Error opening file. Program aborting.\n";
system("pause");
exit(1);
}
int choice;
do
{
choice = menu();
proccessChoice(choice);
} while(choice != 3);
system("pause");
return 0;
}
int menu()
{
int c;
cout << "1.Enter new fraction" << endl;
cout << "2.Find fraction location" << endl;
cout << "3.Quit" << endl;
cin >> c;
return c;
}
void proccessChoice(int i)
{
switch(i)
{
case 1:
{
cout << "Please enter a fraction to be stored: ";
fracs[index] = readFrac();
file.write(reinterpret_cast<char*>(fracs[index]), sizeof(Fraction));
/*cout << fracs[index]->num << "/" << fracs[index]->den ;*/
index++;
}
break;
case 2:
{
cout << "Please enter a fraction to find: ";
Fraction* fToFind = readFrac();
int i = search(file, fToFind);
cout << "The fraction is at position: "<< i << endl;
}
break;
}
}
int search(fstream& file, Fraction* f)
{
Fraction* cur = new Fraction();
int pos = -2;
if (!file)
{
cout << "Error opening file. Program aborting.\n";
system("pause");
exit(1);
}
while(!file.eof())
{
file.read(reinterpret_cast<char *>(cur), sizeof(Fraction));
if((cur->num == f->num) && (cur->den == f->den))
{
cout << "\nFrac found!" << cur->num << "/" << cur->num<<endl;
pos = file.tellg();
return pos;
}
}
return pos;
}
Fraction* readFrac()
{
Fraction* f = new Fraction();
char slash;
cin >> f->num >> slash >> f->den;
return f;
}
You're not starting the search from the beginning of the file. You need:
file.seekg( 0, std::ios::beg );
Similarly I think you're not appending to the end when writing to the file.
file.seekp( 0, std::ios::end );
I can write into a relative file1, then when I try to read the content and display it on the screen (to check if data are actually into the file), I do not have the records which I believe are already present in the file. I am using Dev-C++. Any help will be appreciated. The code is below;
#include <iostream> // cin, cout
#include <iomanip>
#include <fstream>
#include <conio.h>
using namespace std;
#define SIZE 10
struct client // Client record
{
int account; // from 1 to SIZE
char name[20];
double balance;
};
void make_file(char filename[], int number_of_records)
{
cout << "\nMAKE_FILE: Creating a blank relative file " << filename
<< " containing " << number_of_records << " records.";
ofstream OS(filename, ios::out);
if(!OS) {cerr << "File open error." << endl; exit(1);}
client blank={0, "", 0.0}; // Create an empty client record
while(number_of_records--)
OS.write((char *)&blank, sizeof(blank));
cout << "\nFile created.";
OS.close();
}
int main(void)
{
client c;
void *ptr;
int n=0;
char *fname = "credit.txt";
make_file(fname, SIZE);
fstream iof("credit.txt",ios::in | ios::out);
if(!iof)
{
cerr<<"File open error! "<<endl;
exit(1);
}
cout<<"\n\nenter the 10 customers into the file: "<< fname<<endl<<endl;
while(0 < c.account) // && c.account <= maxrec)
{
iof.seekp((c.account-1) * sizeof(client)); // position the pointer
iof.write((char *)&c, sizeof(c));
cout << "Account[1.."<< SIZE
<< "], Name, Balance (0 0 0 to exit)= ";
cin >> c.account >> c.name >> c.balance;
}
cout << "\n\nSHOW_FILE: The contents of file " << fname;
iof.seekg (0, ios::beg);
while(iof.read((char *)&c, sizeof(c))) //where I think the problem is
{
cout <<'\n'<< setw(3)<< ++n << setw(6) << c.account <<setw(20)
<< c.name << setw(10) << c.balance ;
// << " | " << IS.eof() << " " << ptr;
}
iof.close();
cout << "\n\n";
system("pause");
return 0;
}
A relative file is a file in which each record is identified by its ordinal position in the file allowing for random as well as sequential access.
Relative Files
Relative file organization
http://cayfer.bilkent.edu.tr/~cayfer/ctp108/relative.htm
You need to use binary reading/writing.
fstream iof("credit.txt",ios::in | ios::out | ios::binary);
In your code, in first loop, c.account is not initialitzed. Perhaps you are overwriting file with uninitialized values:
while(0 < c.account) // <--- c.account is not initialized!!
{
iof.seekp((c.account-1) * sizeof(client)); // position the pointer
iof.write((char *)&c, sizeof(c)); // <-- overwriting data??
You're program intrigued me since I haven't done too much work with iostream. If you were ever working with data that had to be edited on a per record basis you'd use some type of database or specialized library that would encapsulate you from all this stuff, such as an xml library. Since your data is so small it's easier to just load all of it into your application using an array of your data structs. After, when you've got new user input, it's easiest clear the file, and the write the data fresh. Here is what I did.
#include <stdio.h>
#include <tchar.h>
#include <iostream> // cin, cout
#include <iomanip>
#include <fstream>
#include <conio.h>
using namespace std;
#define SIZE 10
#define BUFFER_SIZE 100
#define NAME_SIZE 20
struct client // Client record
{
int account; // from 1 to SIZE
char name[NAME_SIZE];
double balance;
};
/* Makes file if files does not exist.
* Returns true if file already exists
*/
bool make_file(char filename[], int number_of_records)
{
// Check if file exists
fstream file;
file.open(filename, ios_base::out | ios_base::in); // will not create file
if (file.is_open())
{
file.close();
return true;
}
else
{
file.clear();
file.open(filename, ios_base::out);
if(!file) {cerr << "File open error." << endl; exit(1);}
cout << "File created. \n";
file.close();
return false;
}
}
/* Create an application that reads x number of accounts from a text file
* into an array of client data structures.
*/
int _tmain(int argc, _TCHAR* argv[])
{
client clientArray[SIZE];
char cleanName[NAME_SIZE];
for(int i = 0; i < NAME_SIZE; i++)
cleanName[i] = NULL;
// Make file if doesn't not exist.
char *fname = "credit.txt";
bool fileExisted = false;
fileExisted = make_file(fname, SIZE);
// initialize client array
for(int j = 0; j < SIZE; j++)
{
clientArray[j].account = -1;
strcpy_s(clientArray[j].name, cleanName);
clientArray[j].balance = 0.0;
}
// Open file and populate the client array
fstream readFile("credit.txt", ios::in | ios::binary);
if(fileExisted)
{
if(!readFile)
{
cerr<<"File open error! "<<endl;
exit(1);
}
int index = 0;
bool firstRun = true;
client temp;
while(index < SIZE)
{
readFile >> temp.account;
readFile >> temp.name;
readFile >> temp.balance;
if(readFile.eof())
break;
if(firstRun)
{
cout << "Data read \n";
cout << "----------\n";
firstRun = false;
}
clientArray[index].account = temp.account;
strcpy_s(clientArray[index].name, temp.name);
clientArray[index].balance = temp.balance;
cout << setw(3) << index+1;
cout << setw(6) << clientArray[index].account;
cout << setw(20) << clientArray[index].name;
cout << setw(10) << clientArray[index].balance << "\n";
index++;
}
readFile.close();
readFile.clear();
}
// Get user input
{
client temp; // Create and initialize temp client
temp.account = 0;
temp.balance = 0;
strcpy_s(temp.name, cleanName);
int index = 0;
bool keepLooping = true;
while(keepLooping)
{
cout << "Account[1.."<< SIZE << "], Name, Balance (-1 to exit)= ";
cin >> temp.account;
// If user exited
if(temp.account == -1)
keepLooping = false;
else
{
cin >> temp.name; // If not keep reading data
cin >> temp.balance;
// Find either unused account or same account
bool found = false;
int firstEmpty = -1;
for(int i = 0; i<SIZE; i++)
{
if(temp.account == clientArray[i].account) // Same account found
{
strcpy_s(clientArray[i].name, temp.name);
clientArray[i].balance = temp.balance;
found = true;
break;
}
else if((clientArray[i].account == -1)&&(firstEmpty == -1)) // Empty account found
{
firstEmpty = i;
}
}
if((firstEmpty != -1)&&(!found)) // Copy input to empty account
{
clientArray[firstEmpty].account = temp.account;
strcpy_s(clientArray[firstEmpty].name, temp.name);
clientArray[firstEmpty].balance = temp.balance;
}
else if(found) //
{
cout << "Updating Client Data. \n";
}
else // No empty accounts break loop
{
cout << "Client array is full!\n";
keepLooping = false;
}
}
}
} // end of user input scope
// Clear file and write only valid data to new file
{
ofstream out;
out.open("credit.txt");
for(int i=0 ; i<SIZE ; i++)
{
if(clientArray[i].account != -1)
{
out << clientArray[i].account << "\t";
out << clientArray[i].name << "\t";
out << clientArray[i].balance << "\n";
}
}
out.close();
out.clear();
}
// Open file and read the data
{
ifstream readFile("credit.txt", ios::in | ios::binary);
// readFile("credit.txt", ios::in | ios::binary);
if(!readFile)
{
cerr<<"File open error! "<<endl;
exit(1);
}
if(!readFile.good())
{
cerr<<"File open error!2"<<endl;
exit(1);
}
int index = 0; // scope variables
client temp;
temp.account = 0;
temp.balance = 0;
strcpy_s(temp.name, cleanName);
cout << "\nAccounts" << "\n";
cout << "----------" << "\n";
bool readFileb = readFile.good();
while(index < SIZE)
{
readFile >> temp.account;
readFile >> temp.name;
readFile >> temp.balance;
if(readFile.eof())
break;
cout << setw(3) << index+1;
cout << setw(6) << temp.account;
cout << setw(20) << temp.name;
cout << setw(10) << temp.balance << "\n";
index++;
}
readFile.close();
readFile.clear();
}
system("pause");
}