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.

I'm taking a look at some of the code, my initial thoughts on your first problem are that the file stream has error bits set that need cleared.

Firstly as a matter of good style let's initialize your char array to '\0'. char fname[30] = {'\0'}; What this code does is ensure initializing the first element to '\0', and the way C++ works means it will zero the rest of the elements of the array that were not specifically initialized.

It appears the errors is indeed un-cleared file stream errors.

if (!fio)
			{
				cout << "File does not exist, try again? (y/n) ";
				again = getYesNo();
				cin.clear();
				cin.ignore();
				fname[0] = '\0';
			}

"fio" likely has error bits set that need be cleared, just like cin.


Hopefully this will make clear the issue:

if (choice == 'Y')
	{
		cin.clear();
		cin.ignore();
		do 
		{
			fio.clear();//<-- clear error bits.
			cout << "Enter the name of the existing file: ";
			cin.getline(fname, 30);
			fio.open(fname, ios::out | ios::in | ios::binary);//<-- set error bits on error.
			if (!fio)
			{
				cout << "File does not exist, try again? (y/n) ";
				again = getYesNo();
				cin.clear();
				cin.ignore();
				//As a matter of good style let's zero the array.
				memset(fname, 0, 30);
			}
		}while (again == 'Y' && !fio);//<-- test for error bits.
	}

Looks like this line was neglected:

fio.open(fname, ios::out || ios::binary || ios::trunc);

fio.open(fname, ios:: in | ios::out | ios::binary | ios::trunc); Some stuff is still left in your input streams. Not to worry:

if (choice == 'Y')
	{
		cin.clear();
		cin.ignore();
		do 
		{
			fio.clear();//<-- clear error bits.
			cin.clear();
			cin.sync();//<-- sync with source of characters.

			cout << "Enter the name of the existing file: ";
			cin.getline(fname, 30);
			fio.open(fname, ios::out | ios::in | ios::binary);//<-- set error bits on error.
			if (!fio)
			{
				cout << "File does not exist, try again? (y/n) ";
				again = getYesNo();
				//As a matter of good style let's zero the array.
				memset(fname, 0, 30);
			}
		}while (again == 'Y' && !fio);//<-- test for error bits.
	}
	else
	{
		do 
		{
			fio.clear();//Clear error bits.
			cin.clear();
			cin.sync();

			cout << "Enter the name of a new file: ";
			cin.getline(fname, 30);
			fio.open(fname, ios::in | ios::out | ios::binary | ios::trunc);
			if (!fio)
			{
				cout << "File creation failed, try again? (y/n) ";
				again = getYesNo();
				memset(fname,0,30);
			}
		}while (again == 'Y' && !fio);
	}

Edited 5 Years Ago by pseudorandom21: n/a

Comments
Thanks a lot for the help! :)

pseudorandom21, you are a wizard! Thanks to your post, my first 2 problems just evaporated, and now that I'm less stressed, the third problem should fall easily! Thanks a lot!

This article has been dead for over six months. Start a new discussion instead.