I thought this program was as good as done, turns out, it's more broken than I thought! Right now I'm in a panic, since it's due tomorrow, and I have a few big problems with it.
Problem 1:
I need to either open an existing file, or a new one depending on what the user wants. Opening an existing file works to a certain extent. If the user screws up and enters a bad file name, it says it can't find the file and prompts them if they want to try again, if they say yes, I'm screwed because even if I enter a correct file name, it'll say file not found no matter what. Breakpoints show the fname variable has EXACTLY what I wrote, so I'm stumped here.
Problem 2:
Opening a new file, I skirted around this problem in previous programs by opening a file for output only, ensuring creation, then closing it and reopening it correctly. I can't do that for this program, so I ask, is there a certain ios command I can use to ensure the creation of a file, while still having binary, in, and out?
Problem 3:
If the user enters choice 7, the program should show a count of how many active records there are, how many deleted records there are, and the total. This is giving me problems because if I have 3 active records, it shows 3 active, 0 deleted, 3 total, perfect! Since the program asks the user what the record number is, let's just assume we have 1, 3, and 45. I delete 3, it shows 2, 1, 3, again perfect. Deleting record 1 as well causes it to screw up, it still shows 2 active, 1 deleted, 3 total, despite having 2 of them deleted. Deleting the remaining record causes it to be correct again.
Now rewind a bit, say I delete record 1 first, now it screws up and still says 3 active, 0 deleted, 3 total. So something about record 1 is throwing a monkey wrench into my program.
First off, here's the code pertinent to the first two problems, the opening of the file:
cout << "Are you opening an existing file? \n(y/n, n will prompt you for the name of a newly created file)";
choice = getYesNo();
if (choice == 'Y')
{
cin.clear();
cin.ignore();
do
{
cout << "Enter the name of the existing file: ";
cin.getline(fname, 30);
fio.open(fname, ios::out | ios::in | ios::binary);
if (!fio)
{
cout << "File does not exist, try again? (y/n) ";
again = getYesNo();
cin.clear();
cin.ignore();
fname[0] = '\0';
}
}
while (again == 'Y' && !fio);
}
else
{
do
{
cout << "Enter the name of a new file: ";
cin.getline(fname, 30);
fio.open(fname, ios::out || ios::binary || ios::trunc);
if (!fio)
{
cout << "File does not exist, try again? (y/n) ";
again = getYesNo();
}
}
while (again == 'Y' && !fio);
}
if (!fio)
{
system("pause");
return 0;
}
Here's the code pertaining to problem 3, the count:
case 7:
{
int total = 0;
int deleted = 0;
record = 0;
fio.seekg(0);
fio.read((char*) (&e1), sizeof(e1));
do
{
fio.read((char*) (&e1), sizeof(e1));
active = e1.isDeleted();
switch(active)
{
case 1:
deleted++;
total++;
break;
case 2:
record++;
total++;
break;
}
}while (fio);
cout << "Number of active records on file: " << record << endl;
cout << "Number of deleted records on file: " << deleted << endl;
cout << "Total number of records on file: " << total << endl;
}
If you want a general view of everything in this program, I'll post the whole thing down here just in case:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <conio.h>
using namespace std;
class employee
{
private:
char fName[20];
char lName[20];
int age;
double wage;
int active;
//0 means the record is completely empty, 1 means the record has data, but has been deleted by the user, 2 means the record
//has data and is active.
public:
employee(char[20], char[20], int, double, int);
void getInput();
void display(int);
void displayDeleted(int);
void delRec();
int isDeleted();
};
employee::employee(char fName[20], char lName[20], int age, double wage, int active)
{
}
int menuChoice();
char getYesNo();
int getNumerical();
float getFloat();
int main()
{
char choice = ' ';
char again = ' ';
char fname[30];
int record = 0;
int deleted = 0;
int menu = 0;
int active = 0;
employee e1('\0', '\0', 0, 0.00, 0);
fstream fio;
fname[0] = '\0';
cout << "Are you opening an existing file? \n(y/n, n will prompt you for the name of a newly created file)";
choice = getYesNo();
if (choice == 'Y')
{
cin.clear();
cin.ignore();
do
{
cout << "Enter the name of the existing file: ";
cin.getline(fname, 30);
fio.open(fname, ios::out | ios::in | ios::binary);
if (!fio)
{
cout << "File does not exist, try again? (y/n) ";
again = getYesNo();
cin.clear();
cin.ignore();
fname[0] = '\0';
}
}
while (again == 'Y' && !fio);
}
else
{
do
{
cout << "Enter the name of a new file: ";
cin.getline(fname, 30);
fio.open(fname, ios::out || ios::binary || ios::trunc);
if (!fio)
{
cout << "File does not exist, try again? (y/n) ";
again = getYesNo();
}
}
while (again == 'Y' && !fio);
}
if (!fio)
{
system("pause");
return 0;
}
while (menu != 8)
{
do
{
menu = menuChoice();
}while (menu < 1 && menu > 8);
switch(menu)
{
case 1:
{
do{
cout << "Enter record number: " << endl;
record = getNumerical();
fio.seekp((record - 1) * sizeof(e1));
e1.getInput();
fio.write((char*)(&e1), sizeof(e1));
cout << "Enter another? (y/n): ";
again = getYesNo();
}while (again == 'Y');
break;
}
case 2:
{
do{
do
{
cout << "Enter record number to read ";
record = getNumerical();
fio.seekg((record - 1) * sizeof(e1));
fio.read((char*)(&e1), sizeof(e1));
active = e1.isDeleted();
if (active != 2)
{
cout << "Record does not exist, try again? (y/n) ";
choice = getYesNo();
}
}
while (choice == 'Y' && active != 2);
if (choice == 'N')
break;
e1.display(record);
cout << "Read another? (y/n) ";
again = getYesNo();
}while (again == 'Y');
break;
}
case 3:
{
do{
do
{
cout << "Enter record number to modify ";
record = getNumerical();
fio.seekg((record - 1) * sizeof(e1));
fio.read((char*)(&e1), sizeof(e1));
active = e1.isDeleted();
if (active != 2)
{
cout << "Record does not exist, try again? (y/n) ";
choice = getYesNo();
}
}
while (choice == 'Y' && active != 2);
if (choice == 'N')
break;
fio.seekg((record - 1) * (sizeof(e1)));
fio.read((char*)(&e1), sizeof(e1));
cout << "You are modifying this record:" << endl << endl;
e1.display(record);
cout << "Is this correct? (y/n) ";
choice = getYesNo();
if (choice == 'Y')
{
fio.seekp((record - 1) * (sizeof(e1)));
e1.getInput();
fio.write((char*)(&e1), sizeof(e1));
cout << "The record has been modified" << endl;
}
cout << "Modify another? (y/n) ";
again = getYesNo();
}while (again == 'Y');
break;
}
case 4:
{
do{
cout << "Enter record number to delete ";
record = getNumerical();
fio.seekg((record - 1) * (sizeof(e1)));
fio.read((char*)(&e1), sizeof(e1));
active = e1.isDeleted();
if (active == 2)
{
cout << "You are deleting this record: " << endl << endl;
e1.display(record);
cout << "Is this correct? (y/n) ";
choice = getYesNo();
if (choice == 'Y')
{
fio.seekp((record - 1) * (sizeof(e1)));
e1.delRec();
fio.write((char*)(&e1), sizeof(e1));
cout << "The record has been deleted" << endl;
}
}
else
cout << "record is already deleted" << endl;
cout << "Delete another? (y/n) ";
again = getYesNo();
}while (again == 'Y');
break;
}
case 5:
{
do{
do
{
cout << "Enter record number to undelete ";
record = getNumerical();
fio.seekg((record - 1) * (sizeof(e1)));
fio.read((char*)(&e1), sizeof(e1));
active = e1.isDeleted();
if (active == 2)
{
cout << "This record is not deleted, try again? (y/n)" << endl;
choice = getYesNo();
}
else if (active == 0)
{
cout << "This record does not exist, try again? (y/n)" << endl;
choice = getYesNo();
}
}
while (choice == 'Y' && active != 1);
if (choice == 'N')
break;
cout << "You're undeleting this record: " << endl << endl;
e1.displayDeleted(record);
cout << "Is this correct? (y/n) ";
choice = getYesNo();
if (choice == 'Y')
{
e1.delRec();
fio.seekp((record - 1) * (sizeof(e1)));
fio.write((char*)(&e1), sizeof(e1));
cout << "The record has been undeleted." << endl;
}
cout << "Undelete another? (y/n) ";
again = getYesNo();
}while (again == 'Y');
break;
}
case 6:
{
fio.seekg(0);
fio.read((char*) (&e1), sizeof(e1));
record = 1;
while(fio)
{
e1.display(record);
fio.read((char*) (&e1), sizeof(e1));
record++;
}
break;
}
case 7:
{
int total = 0;
int deleted = 0;
record = 0;
fio.seekg(0);
fio.read((char*) (&e1), sizeof(e1));
do
{
fio.read((char*) (&e1), sizeof(e1));
active = e1.isDeleted();
switch(active)
{
case 1:
deleted++;
total++;
break;
case 2:
record++;
total++;
break;
}
}while (fio);
cout << "Number of active records on file: " << record << endl;
cout << "Number of deleted records on file: " << deleted << endl;
cout << "Total number of records on file: " << total << endl;
}
default:
{
break;
}
}
fio.seekg(0);
fio.seekp(0);
fio.clear();
fio.flush();
system("pause");
}
return 0;
}
void employee::getInput()
{
char again;
//The clear and ignore are needed here because cin and cin.getline don't mesh well, which without this would lead to
//the program just skipping the name input.
cin.clear();
cin.ignore();
cin.sync();
cout << "Enter the name of the employee. ";
cin.getline(fName, 20);
cout << "Enter the last name of the employee. ";
cin.getline(lName, 20);
do{
cout << "Enter the age of the employee. ";
age = getNumerical();
if (cin.fail())
{
cout << "You must enter a number ";
}
}while (cin.fail());
do{
cout << "Enter the wage of the employee. ";
wage = getFloat();
if (cin.fail())
{
cout << "You must enter a number ";
}
}while (cin.fail());
active = 2;
}
void employee::display(int record)
{
if (active == 2)
cout << left << setw(8) << "Record: " << setw(3) << record << " Name: " << fName << " " << lName << " Age: " << setw(4) << age << " Wage: " << setw(8) << fixed << setprecision(2) << wage << endl;
}
void employee::displayDeleted(int record)
{
if (active == 1)
cout << left << setw(8) << "Record: " << setw(3) << record << " Name: " << fName << " " << lName << " Age: " << setw(4) << age << " Wage: " << setw(8) << fixed << setprecision(2) << wage << endl;
}
int menuChoice()
{
int menu;
cout << "\nOperation Menu: \n 1. Add a record \n 2. Read a record \n 3. Change a record \n 4. Delete a record \n 5. Undelete a record \n 6. List all records \n 7. Total record count on file \n 8. Exit" << endl;
cout << "\nEnter a choice ";
do{
menu = getNumerical();
if (menu < 0 || menu > 8)
cout << "The choice must be between 1 and 8 ";
}while (menu < 0 || menu > 9);
return menu;
}
void employee::delRec()
{
if (active == 2)
active = 1;
else if (active == 1)
active = 2;
}
char getYesNo()
{
char again;
while(true)
{
again = ' ';
cin >> setw(1) >> again;
switch(toupper(again))
{
case 'Y':
{
return 'Y';
break;
}
case 'N':
{
return 'N';
break;
}
default:
cin.clear();
cin.ignore();
cin.sync();
break;
}
}
}
int getNumerical()
{
bool fail;
int number;
do{
cin >> number;
if (cin.fail())
{
fail = true;
cin.clear();
cin.ignore(1000, '\n');
cout << "You must enter a number ";
}
else
fail = false;
}while (fail == true);
return number;
}
float getFloat()
{
bool fail;
float number;
do{
cin >> number;
if (cin.fail())
{
fail = true;
cin.clear();
cin.ignore(1000, '\n');
cout << "You must enter a number ";
}
else
fail = false;
}while (fail == true);
return number;
}
int employee::isDeleted()
{
return active;
}
Thanks in advance.