I'm taking an advanced C++ class now, and everything up to now has been pretty simple (mostly review stuff), but now we got to binary file io and it's kicking my butt.

This program is supposed to read from a file called "Hardware.dat" (or create it if it doesn't exist), and allow the user to manipulate the data by adding a new record, modifying an existing record, deleting a record, and display all the records. Each record contains the record number, name, quantity, cost, and a flag telling if it's active or not.

Adding a record is no problem. Modifying shows the record it's supposedly modifying, asks for input, but does nothing to actually modify the record. Deleting is also supposed to show the record your deleting, but instead, it throws this jargon at me:

Record: 1632108544 Name: mmer Quantity: 1030815744 Cost: 2.2

The record in question was this:

Record: 3 Name: Hammer Quantity: 51 Cost: 12

Naturally, it does nothing in the way of deleting the record either.

Printing the records is okay, though somehow I broke the functionality I had that allowed it to print sequentially, like if you entered record 8, then 3, then 10, it would print 3, 8, 10. Now, it just prints in the order you entered, regardless of number.

With that out of the way, here's the code:

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <conio.h>

using namespace std;


class tool
{
private:
	
	int record;
	char name[30];
	int qty;
	double cost;
public:
	//bool active;
	tool(int=0);
	void getInput(fstream&, tool, bool, int);
	void display(bool);
};

tool::tool(int rec)
{
	record = rec;
}

int main()
{
	bool active = false;
	int number = 0;
	int again = 1;
	int menu = 0;
	tool t1;
	fstream fio;
	fio.open("hardware.dat", ios::out | ios::in | ios::binary | ios::app);
	if(!fio)
	{
		fio.open("hardware.dat", ios::out);
		cout << "file has been created, run the program again to start inputting tools." << endl;
	}
	else
	{
		

	fio.seekp(0, ios::end);
	cout << "Operation Menu: \n 1. Add a record \n 2. Modify a record \n 3. Delete a record \n 4. List records \n 5. Quit" << endl;
	while (menu != 5)
	{
			cout << "\nEnter a choice ";
			cin >> menu;
			switch(menu)
			{
			case 1:
				{
					t1.getInput(fio, t1, false, 0);
					
					active = true;
					fio.write((char*)(&t1), sizeof(t1));
					fio.write((char*)(&active), sizeof(active));
					break;
				}
			case 2:
				{
					cout << "Enter record number to modify";
					cin >> number;
					
					fio.seekg((number + 1) * sizeof(t1));
					fio.read((char*)(&t1), sizeof(t1));
					cout << "You are modifying this record:" << endl << endl;
					t1.display(true);
					fio.seekp((number + 1) * sizeof(t1));
					t1.getInput(fio, t1, true, number);
					
					active = true;
					fio.write((char*)(&t1), sizeof(t1));
					fio.write((char*)(&active), sizeof(active));
					break;
				}
			case 3:
				{
					cout << "Enter record number to delete";
					cin >> number;
					fio.seekg(number + 1 * sizeof(t1));
					fio.read((char*)(&t1), sizeof(t1));
					t1.display(active);
					fio.seekp(number + 1 * sizeof(t1));
					active = false;
					fio.write((char*)(&t1), sizeof(t1));
					fio.write((char*)(&active), sizeof(active));
					cout << "Has been deleted" << endl;
					break;
				}
			case 4:
				{
					fio.seekg(0);
					fio.read((char*) (&t1), sizeof(t1));
					fio.read((char*)(&active), sizeof(active));
					while(fio)
					{
						t1.display(active);
						fio.read((char*)(&t1), sizeof(t1));
						fio.read((char*)(&active), sizeof(active));
					}
					break;
				}
			case 5:
				{
					break;
				}
			default:
				{
					break;
				}
			}
			fio.seekg(0);
			fio.seekp(0);
		}
	}
	

	system("pause");
	return 0;

	

}

void tool::getInput(fstream& fio, tool t1, bool modify, int number)
{
	if(modify == false)
	{
		int begin, end = 0;
		cout << "Enter record number. ";
		cin >> record;
		fio.seekp(record * sizeof(t1));
	}
	else
		record = number;
	cin.ignore(100, '\n');
	cout << "Enter the name of the tool. ";
	cin.getline(name, 30);
	cout << "Enter the quantity of the tool. ";
	cin >> qty;
	cout << "Enter the cost of the tool. ";
	cin >> cost;
}

void tool::display(bool active)
{
		if (active == 1)
			cout << left << setw(8) << "Record: " << setw(3) << record << " Name: " << setw(30) << name << " Quantity: " << setw(4) << qty << " Cost: " << setw(8) << setprecision(2) << cost << endl;
}

It's probably a mess, I've been changing stuff around trying to get it to work, to no avail. Hopefully someone can point me in the right direction, I just can't figure out how to make it work. Thanks in advance.

Your seekg positioning is off. When you add records, you use:

fio.write((char*)(&t1), sizeof(t1));
    fio.write((char*)(&active), sizeof(active));

but when you look for records in your modify and delete, you use:

fio.seekg((number + 1) * sizeof(t1));

all well and good, but you are not accounting for the 1 byte boolean (active) that you write at the end of each record. Your seek code should look like:

fio.seekg((number + 1) * (sizeof(t1) + sizeof(active)));

You might consider moving the "active" flag inside your tool class - then your calculations work.

Some other things - the "tool" instance you pass into your getInput method is useless (other than to calculate the size of the tool object) - also the calculation is incorrect here, as well. You can use "sizeof(tool) + sizeof(boolean)".

Your "getInput" method - when you add a new record (when "modify" is false) - what happens when I add 2 records, and I type in a record number of "1" for both? It appears that I will overwrite the first record with the second. An add operation should seek to EOF and add there.

That should be enough to get you going.

Thanks, mcriscolo, now it shows a record like I typed it, but I've run into another problem I've been bashing my head against for about an hour now.

Say I have 2 records, number 23, and 42, written in that order. I want to modify (or delete) 42, it shows the record. If I want to change 23, I'm SOL, because typing 23 also brings up record 42. Typing 186 brings up record 42. It's just showing the last tool entered, no matter what I do, but at least I'm not deleting or modifying the records mistakenly, that still doesn't work either. Here's the code I have now (I put the active boolean in the class like you suggested, all my seekp/gs seem to line up now, but it's just reading the last record entered no matter what.):

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <conio.h>

using namespace std;


class tool
{
private:
	
	int record;
	char name[30];
	int qty;
	double cost;
public:
	bool active;
	tool(int=0, bool=false);
	void getInput(fstream&, tool, bool, int);
	void display();
};

tool::tool(int rec, bool act)
{
	record = rec;
	active = act;
}

int main()
{
	int number = 0;
	int again = 1;
	int menu = 0;
	tool t1;
	fstream fio;
	fio.open("hardware.dat", ios::out | ios::in | ios::binary | ios::app);
	fio.seekg(0);
	fio.seekp(0);
	if(!fio)
	{
		fio.open("hardware.dat", ios::out);
		cout << "file has been created, run the program again to start inputting tools." << endl;
	}
	else
	{
		

	fio.seekp(0, ios::end);
	cout << "Operation Menu: \n 1. Add a record \n 2. Modify a record \n 3. Delete a record \n 4. List records \n 5. Quit" << endl;
	while (menu != 5)
	{
			cout << "\nEnter a choice ";
			cin >> menu;
			switch(menu)
			{
			case 1:
				{
					t1.getInput(fio, t1, false, 0);
					
					fio.write((char*)(&t1), sizeof(t1));
					break;
				}
			case 2:
				{
					cout << "Enter record number to modify";
					cin >> number;
					
					fio.seekg((number - 1) * (sizeof(t1)));
					fio.read((char*)(&t1), sizeof(t1));
					cout << "You are modifying this record:" << endl << endl;
					t1.display();
					fio.seekp((number - 1) * (sizeof(t1)));
					t1.getInput(fio, t1, true, number);
				
					fio.write((char*)(&t1), sizeof(t1));
					t1.active = true;
					break;
				}
			case 3:
				{
					cout << "Enter record number to delete";
					cin >> number;
					fio.seekg((number - 1) * (sizeof(t1)));
					fio.read((char*)(&t1), sizeof(t1));
					t1.display();
					fio.seekp((number - 1) * (sizeof(t1)));
					t1.active = false;
					fio.write((char*)(&t1), sizeof(t1));
					cout << "Has been deleted" << endl;
					break;
				}
			case 4:
				{
					fio.seekg(0);
					fio.read((char*) (&t1), sizeof(t1));

					while(fio)
					{
						t1.display();
						fio.read((char*) (&t1), sizeof(t1));
					}
					break;
				}
			case 5:
				{
					break;
				}
			default:
				{
					break;
				}
			}
			fio.seekg(0);
			fio.seekp(0);
			fio.clear();
			fio.flush();
		}
	}
	

	system("pause");
	return 0;

	

}

void tool::getInput(fstream& fio, tool t1, bool modify, int number)
{
	if(modify == false)
	{
		int begin, end = 0;
		cout << "Enter record number. ";
		cin >> record;
		fio.seekp((record - 1) * (sizeof(t1)));
	}
	else
		record = number;
	cin.ignore(100, '\n');
	cout << "Enter the name of the tool. ";
	cin.getline(name, 30);
	cout << "Enter the quantity of the tool. ";
	cin >> qty;
	cout << "Enter the cost of the tool. ";
	cin >> cost;
	active = true;
}

void tool::display()
{
		if (active == true)
			cout << left << setw(8) << "Record: " << setw(3) << record << " Name: " << setw(30) << name << " Quantity: " << setw(4) << qty << " Cost: " << setw(8) << setprecision(2) << cost << endl;
}

(Sorry for dumping the whole code again, I have no idea where it's going wrong, but it's going wrong very badly).

Take the "ios::app" option out of your open statement. It's forcing all the writes to go to the end of the file (for adds that's OK, but when you delete or modify a record, it's actually writing them to the end of the stream). Once you do that, it should work a lot better.

Thanks again! The App was needed so the program would create the file if it didn't exist, but after closing it, and reopening it with everything but the app, it worked perfectly! :)

This question has already been answered. Start a new discussion instead.