Reputation: 23
I've been working on my school CS Project for a couple of weeks, and I coded a text based program to manage a supermarket/shop in C++. I ran into some trouble when I was trying to store the database and read it from file storage.
Complete source here
I am aware that TurboC++ is an extremely outdated compiler, but it's a part of my prescribed syllabus, so there's no way out of it. (Thankfully, the next batch out will be learning python)
My main concept was to use a self referencial structure as the node for a singly linked list handled by a class and its functions.
struct product //Self referencial structure to store the product details
{
unsigned int code;
char name[100];
char category[40];
unsigned int quantity;
double price;
product *next;
};
class list //Class to handle the linked list of products
{
private:
product *head, *tail;
public:
list()
{
head = NULL; //By default the list will be empty
tail = NULL;
}
void DelList();
void AppProduct(product *, unsigned int);
void AddProduct(unsigned int);
product* FindProduct(unsigned int);
double CalcTotal();
void ListProducts();
void ModProduct(product *);
void SaveToFile();
void LoadFromFile();
product* PointToNewProduct(product);
product* GetProductFromFile(ifstream &);
product* GetHead()
{
return head;
}
void Clear();
};
store
and cart
are globally declared objects of class list
storing the separate linked list.
I chose the linked list format primarily for the program, and decided to add saving to file and loading from file only later when I found out file handling was a compulsory part of the project. This is the code I wrote for the same -
void list::SaveToFile() //self explanatory
{
ofstream fout("DATABASE.DAT", ios::trunc);
product * cur = head;
product temp;
while( cur != NULL )
{
temp = *cur;
fout.write( (char *)&temp, sizeof(product) );
cur = cur->next;
}
fout.close();
}
product * list::PointToNewProduct(product temp) //copy the temp product details into a new pointer and return the pointer
{
product * cur = new product;
cur->code = temp.code;
strcpy(cur->name, temp.name);
strcpy(cur->category, temp.category);
cur->price = temp.price;
cur->quantity = temp.quantity;
cur->next = NULL;
return cur;
}
product * list::GetProductFromFile(ifstream& fin) //retrieve a single product from the given file
{
if( fin.eof() )
return NULL;
product temp;
fin.read( (char *)&temp, sizeof(product) );
cout<<temp.name;
return PointToNewProduct(temp);
}
void list::LoadFromFile() //Function to load struct from file and rebuild the linked list (only returning one item right now)
This is the code I wrote for the same - //Update: I thought I fixed it, but its up to two items now, still not all
{
ifstream fin("DATABASE.DAT", ios::in); //Initialize the stream
head = GetProductFromFile(fin); //initialize head pointer
product * cur = head;
product * nextptr;
do {
nextptr = GetProductFromFile(fin); //get the next product in file
cur = cur->next = nextptr; //link product with the previous product
tail = cur; //make the current pointer the last one
} while( !fin.eof() );
tail->next = NULL;
fin.close();
}
Now my problem is, that while I am able to write the linked list items to file properly, trying to read it results in it retrieving only 2 nodes, regardless of the number of nodes I have written to file.
A debugging session with my teacher led me to believe that this was because I had not been deleting the older linked list when loading one from file, and this problem of unfreed memory carried forward when writing to file. A destructor I had written to free up memory was never called, since my objects were globally declared, leading me to write the DelList();
function and call it before reading from file. This unfortunately did not solve the problem.
void list::DelList()
{
product * cur = head, * temp;
while(cur != NULL)
{
temp = cur;
cur = cur->next;
delete temp;
}
delete cur;
delete head;
delete tail;
head = NULL;
tail = NULL;
}
This is the code I wrote for the same - I also added some test code as a switchcase choice where I simply read from file without linking, and it also does not display the desired output.
case 7:
clrscr();
ifstream fin("DATABASE.DAT", ios::in);
product temp;
fin.seekg(0, ios::beg);
while( fin.read( (char *)&temp, sizeof(product) ) )
{
//fin.read( (char *)&temp, sizeof(product) );
cout<<temp.name<<'\t'<<temp.category<<'\n';
}
getch();
break;
What's the problem with my code, and how do I fix it?
Upvotes: 1
Views: 229
Reputation: 23
I managed to solve my problem with a workaround, though I still don't know why my original code didn't work, though seemingly the problem is with reading and writing pointers to and from a file.
What I've done to fix the problem is change product
to be a class, inherited from the base class prod
, with prod
containing the same things that the structure used to with the exception of the pointer to the next. Then I wrote a function Delink()
to convert each product
in the linked list to a prod
and write it to file.
Then while reading the file, I convert each prod
I read into a product
and link it back to construct the linked list again. This seems to have fixed my problem.
Upvotes: 1