I have an assignment where I need to create an inventory program where I can add information about a product to a text file, and shown in the file like shown:

1;Hammer;20;13.50

Where 1 is the record number, Hammer is the description, 20 is the quantity, and 13.50 is the cost

In the program, there need to be a menu where I can choose to do the following:
- Add a new record (to the end of the text file)
- Delete a record (by record #)
- Modify a record (change anything except the record #)
- List all records
- Sort Records by COST
- Quit and SAVE to a text file

The problem I'm having (so far), is that once I exit out of the program, and restart it again, I can not modify by record #. On top of that, I can only display the list once, after that the text file is not able to be opened. Haven't even started on the Sorting by COST, but I'm not worried about that. Here's by attempt:

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

struct tool
{//open struct tool

	tool *prev;
	int record;
	char toolname[35];
	int quantity;
	double cost;
	tool *next;

};//close struct tool


class tool_dll
{//open class

	private:
		int max;
		int qty;
		tool *head;
		tool *curr_rec;
		bool addRecord2(int, char[35], int, double);
		tool *templist;


	public:

		tool_dll()
		{//open constructor
			max = 100;
			qty =0;
			head = curr_rec = templist = NULL;
		};//close constructor

		bool addRecord(int, char[35],int, double);
		bool modifyRecord(int);
		bool displayNext(int);
		bool deleteRecord(int);
		bool isFull();
		bool isEmpty();
		bool sortByCost();
		bool QuitandSave();

		~tool_dll()
		{//open destructor
			QuitandSave();
		};//close destructor


};//close class

///////////////////////////////////////////////////////////////////////////
/////////////////////////////MEMBER FUNCTIONS//////////////////////////////
///////////////////////////////////////////////////////////////////////////

bool tool_dll:: addRecord(int r, char t[35],int q, double c)
{
	if(isFull())
		return false;

	if((head == NULL) || (head -> record > r)) //first tool
	{
		qty++;
		tool *temp = new tool;
		temp -> record = r;
		strcpy(temp ->toolname, t);
		temp -> quantity = q;
		temp -> cost = c;

		temp -> prev = NULL;
		temp -> next = head;
		head = temp;

		if(temp -> next != NULL)
			temp ->next -> prev = temp;
		curr_rec = temp;
		return true;
	}


	for(tool *scan = head; scan != NULL; scan = scan ->next)
	{

		if(scan->record == r)
			return false;

		if(scan->next == NULL)
		{
			qty++;
			tool *temp = new tool;
			temp -> record = r;
			strcpy(temp ->toolname, t);
			temp -> quantity = q;
			temp -> cost = c;

			temp -> next = scan -> next;
			if(temp -> next != NULL)
				temp ->next -> prev = temp;

			temp -> prev = scan;
			scan -> next = temp;
			return true;
		}

		if(scan->next->record > r)
		{
			qty++;
			tool *temp = new tool;
			temp -> record = r;
			strcpy(temp ->toolname, t);
			temp -> quantity = q;
			temp -> cost = c;

			temp -> next = scan -> next;
			if(temp -> next != NULL)
				temp ->next -> prev = temp;

			temp -> prev = scan;
			scan -> next = temp;
			return true;

		}

	}


return false;
};

///////////////////////////////////////////////////////////////////////////

bool tool_dll:: addRecord2(int r, char t[35],int q, double c)
{
	if(isFull())
		return false;

	if((templist == NULL) || (templist -> cost > c)) //first tool
	{
		qty++;
		tool *temp = new tool;
		temp -> record = r;
		strcpy(temp ->toolname, t);
		temp -> quantity = q;
		temp -> cost = c;

		temp -> prev = NULL;
		temp -> next = templist;
		templist = temp;

		if(temp -> next != NULL)
			temp ->next -> prev = temp;
		curr_rec = temp;
		return true;
	}


	for(tool *scan = templist; scan != NULL; scan = scan ->next)
	{
		if(scan -> cost == c)
			return false;

		if((scan ->next == NULL) || (scan -> next -> cost > c))
		{
			qty++;
			tool *temp = new tool;
			temp -> cost = c;
			strcpy(temp ->toolname, t);
			temp -> quantity = q;
			temp -> record = r;

			temp -> next = scan -> next;
			if(temp -> next != NULL)
				temp ->next -> prev = temp;

			temp -> prev = scan;
			scan -> next = temp;
			return true;
		}

	}


return false;

};

///////////////////////////////////////////////////////////////////////////

bool tool_dll:: modifyRecord(int r)
{

	displayNext(r);
	cout << endl;


	tool *scan = head;

	while(true)
	{
	//	if(scan == NULL)
	//		return false;

		if(scan->record == r)
			break;

		scan = scan->next;
	}

	int choice=0;
	char name[35];
	int amount;
	double price;
	int ref;
	int i;

	do
	{

		cout << "What Would You Like to Edit for this Tool?" << endl;
		cout << "1) Tool Name" << endl << "2) Quantity" << endl;
		cout << "3) Cost" << endl << "4) Exit" << endl;
		cout << "What is your choice(1,2,3,4): ";
		cin >> choice;

		switch(choice)
		{
			case 1:
				cout << "What Is The New Tool Name: ";
				cin>>name;


				ref = scan->record;
				amount = scan ->quantity;
				price = scan->cost;
				deleteRecord(scan->record);
				addRecord(ref,name,amount,price);
				break;

			case 2:
				cout << "What Is The New Quantiy: ";
				cin >> amount;

				ref = scan->record;
				price = scan->cost;
				for(i = 0; i < 35; i++)
				{

					name[i] = scan->toolname[i];

				}
				deleteRecord(scan->record);
				addRecord(ref,name,amount,price);
				break;

			case 3:

				cout << "What Is The New Cost: ";
				cin >> price;

				ref = scan->record;
				amount = scan ->quantity;
				for(i = 0; i < 35; i++)
				{

					name[i] = scan->toolname[i];

				}
				deleteRecord(scan->record);
				addRecord(ref,name,amount,price);
				break;

			default:
				break;
		}

	}while(choice != 4);

	return false;
};

///////////////////////////////////////////////////////////////////////////

bool tool_dll:: displayNext(int r)
{

	if(curr_rec != NULL)
	{
		cout << endl;
		cout << curr_rec -> record << ";" << curr_rec->toolname << ";";
		cout << curr_rec -> quantity << ";" << curr_rec -> cost;
		curr_rec = curr_rec->next;
		return true;
	}
cout << endl;
return false;
};

///////////////////////////////////////////////////////////////////////////

bool tool_dll:: deleteRecord(int r)
{
	if(isEmpty())
		return false;


	tool *scan= head;


	if(head->record == r)//first tool
	{
		qty--;
		head = scan->next;
		if(scan->next != NULL)
		{
		scan->next->prev = NULL;
		}
		delete scan;
		return true;
	}


	for(scan = scan->next; scan != NULL; scan = scan->next)
	{
		if(scan->record == r)
		{
			if(scan->next == NULL)//last node
			{
				scan->prev->next= NULL;
			}
			else
			{
				scan->prev->next = scan->next;
				scan->next->prev = scan->prev;
			}

			delete scan;
			qty--;
			return true;
		}
	}

return false;
};

///////////////////////////////////////////////////////////////////////////

bool tool_dll:: isFull()
{
	if(qty == max)
		return true;
	return false;
};

///////////////////////////////////////////////////////////////////////////

bool tool_dll:: isEmpty()
{
	if(qty == 0)
		return true;
	return false;
};

///////////////////////////////////////////////////////////////////////////

bool tool_dll:: sortByCost()
{
	templist = NULL;

	while(head != NULL)
	{
		addRecord2(head->record,head->toolname,head->quantity,head->cost);
		deleteRecord(head->record);
	}

	head = templist;
	curr_rec = head;
	return true;

};

///////////////////////////////////////////////////////////////////////////

bool tool_dll:: QuitandSave()
{
	ofstream outFile;

	outFile.open("inventory.txt", ios::app);

	if (!outFile)
	{
		cout << "Can't open file inventory.txt" << endl;
		exit(1);
		return false;
	}


	while(head != NULL)
	{
		outFile << head -> record << ";" << head->toolname << ";"
				<< head -> quantity << ";" << head -> cost << endl;

		deleteRecord(head->record);
	}

	return true;
	outFile.close();



};

////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
////////////////////////////////////////////////////////


int main()
{
	tool_dll database;

	int choice=1;
	int rec_num, qty;
	double cost;
	char desc[35];
	ifstream fin; 
	
	do
	{
	cout <<"Inventory Control Program\n\nPlease Select an Option From the Menu:\n\n";
	cout <<"1: Add New Record\n2: Delete Record by Record Number\n3: Modify A Record";
	cout <<"\n4. List All Records\n5. Sort All Records by Cost\n6: Save and Quit program\n\nChoice: ";
	cin >>choice;


	switch (choice)
	{
		case 1: 
			cout <<"\nEnter A Record Number: ";
			cin >> rec_num;
			cout <<"\nEnter A Product Name: ";
			cin >>desc;
			cout <<"\nEnter the Quantity of "<<desc<<" Needed: ";
			cin >>qty;
			cout <<"\nEnter the Cost of "<<desc<<" per ONE piece: ";
			cin >>cost;

			database.addRecord(rec_num,desc,qty,cost);
			cout <<"\n\nRecord Added.";
		//	database.QuitandSave();
			break;
		case 2:
			cout <<"\nEnter Record Number to Be Deleted: ";
			cin>>rec_num;
			database.deleteRecord(rec_num);
			cout <<"\n\nRecord Deleted.";
			break;
		case 3:
			cout <<"\nEnter Record Number to Be Modified: ";
			cin >>rec_num;
			database.modifyRecord(rec_num);
			cout <<"\n\nRecord Modified.";
			break;
		case 4:
			char c;
			fin.open("inventory.txt", ios::in);
			if(fin.fail())
			{
				cout << "Error: Unable To Open File\n";
				exit(1);
			}

			fin.get(c);

			while(!fin.fail() && !fin.eof())
			{
			cout << c;
			fin.get(c);
			}

			fin.close();
  

		case 5:
		//	database.addRecord2(rec_num,desc,qty,cost);
			break;
		case 6:
			database.QuitandSave();
			break;
		default: "Invalid Choice";
		}
				
	}while (choice!=6);

	return 0; 
}

ANY help at all would be appreciated, especially with being able to access and modify the records after I exit the program and run it again.

Thanks

@ jencas - They are probably required to make their own list, otherwise I don't see why anyone would design their own class for such a thing.

@ XpL0d3r
A few questions I had when looking through your code:
Why are all your functions bool? Normally when I have an insert function, it's a void. The only bool functions I have deal with searching and comparing normally.

Why, when passing toolname, do you store it in a character array? Was that part of the assignment declaration, cause otherwise you could use a string to save some time.

What is the purpose of Sort by Cost? Is it suppose to reorder the main list or only be used while the program runs? And if asked to save and quit after a sortByCost call, should it save the cost sorted version or the original? Just something you might want to think about when working on this part of the code.


You really need to go through you code and simplify it and check it. I ended up trashing it and using one of my already made double linked list cause I was having an issue following it and just changes the code using pieces from yours. Got your code down to 283 lines just so you know.

If you are closing out of the program entirely and then hoping to bring it up and modify the info again after, that isn't going to happen with the way you have it. You would need to add a feature at the beginning that looks for a file called "inventory.txt" and if it is there, reload everything into your list (or that could go through the inventory file, find the right line, reload just that line, and then modify it, but seems overkill). Then that should take care of your issue. I would handle it by letting a function do something like this:

while (getline(inFile, line))
{ // walk through line to change ';' to ' '
  // put line in stringstream
  // store into variables using stringstream
  // clear stringstream.
  addRecord(/*info gathered*/);
}

Regarding your display issues, I see what you did and to fix your problem just add fin.clear(); after you close the file. But all you are doing with that is showing what is stored in "inventory.txt", meaning if you were to save to that file, it would overwrite what was previously stored there. I would change your display feature so it displays what is in the list and do my above suggestion of adding anything in "inventory.txt" to the list at start up.

Your case 4 in the main switch doesn't have an break just so you know.

Might want to consider a function that clears the list entirely just so that if there are 50 nodes and you want a clean list you don't need to delete them one at a time.

Also your destructor doesn't do anything. It just calls save again. What I've been told is a destructor is suppose to free all the memory you used, and yours doesn't. All you need is a while that says until you get to the end of the list, keep deleting and that should be good. And, if you did my above comment about a clearList function, you could just have the destructor call that and it would be fine I believe.

Well, this is just a personal preference, but any time I have a menu in the main and one of the things is "Exit," I just write the code like this cause then it knows to end with that number is called.

main()
{ while (/*something*/)
        { // Menu listed here
           cin >> choice;
           switch(choice)
                     { // all the cases
                        case 6:  // exit call
                             return 0;
                             break;
                        default:
                         // something else.
                     }
         }
}

If something isn't clear, feel free to ask.

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