Structure record binary file, refuses to display contents.

  • (3 Pages)
  • +
  • 1
  • 2
  • 3

39 Replies - 5454 Views - Last Post: 30 September 2012 - 10:21 AM Rate Topic: -----

#31 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3616
  • View blog
  • Posts: 11,263
  • Joined: 05-May 12

Re: Structure record binary file, refuses to display contents.

Posted 29 September 2012 - 06:22 AM

Have you changed the code from post #26? According to that callstack, it was the call to string::resize() from line 150 your code that is causing a problem, but line 150 from post #26 shows a call to fstream::read().
Was This Post Helpful? 0
  • +
  • -

#32 jimblumberg  Icon User is online

  • member icon


Reputation: 4133
  • View blog
  • Posts: 12,865
  • Joined: 25-December 09

Re: Structure record binary file, refuses to display contents.

Posted 29 September 2012 - 07:18 AM

Yes, the problem is when you try to resize the string with an invalid value from your read, so you will need to check the stream state after the first read. If the stream is bad return to the calling function at that point. This is because you have already read the last record with the previous read. Remember that eof() is not triggered until after you read past the end of file.



Jim
Was This Post Helpful? 0
  • +
  • -

#33 mgrex  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 188
  • Joined: 25-March 10

Re: Structure record binary file, refuses to display contents.

Posted 29 September 2012 - 08:31 AM

My current code is identical to post 26.

To Jim, are you saying I should implement an if statement?

I added an extraneous code, that I failed to remove, when trying to find a possible solution, before I posted the call stack, sorry.

This was it in the display function

	while (readRecord(dFile, call)&& !dFile.bad()) //!dFile . eof() ) 
	{
		
		cout << "Description\t: " << call.desc << endl;  
		cout << "Quantity\t: " << call.quantity << endl;  
		cout << "Wholesale cost\t: " << call.wholeCost << endl;  
		cout << "Retail cost\t: " << call.retailCost << endl;  
		cout << "Date\t\t: " << call.dateAdded << endl << endl;  
		i++;
	}



Instead of
void display(fstream& dFile, Items & call)
{
	//int recNum;
	//cout << "Enter the item's record number to view: ";
	//cin >> recNum;

	 //Produces error message

	int i = 0;
	
	while (readRecord(dFile, call)) //!dFile . eof() ) 
	{
		
		cout << "Description\t: " << call.desc << endl;  
		cout << "Quantity\t: " << call.quantity << endl;  
		cout << "Wholesale cost\t: " << call.wholeCost << endl;  
		cout << "Retail cost\t: " << call.retailCost << endl;  
		cout << "Date\t\t: " << call.dateAdded << endl << endl;  
		i++;
	}

	cout << "total iter: " << i << endl;
 
}



With the latter, one can see that a nearly identical call stack is produced.

@ Jim, so you're saying, I should implement some sort of if statement for my display function?

You say I should check the stream state after the first read. A do while statement comes to mind...

Full code
#include <iostream> 
#include <fstream> 
#include <string>
using namespace std;

struct Items
{
	string desc;
	int quantity;
	int wholeCost, retailCost;
	string dateAdded;
};

void options();
void addNew(fstream &, Items &);
void display(fstream &, Items &);
void allContent(fstream &);
bool fileExists(string);
bool readRecord(fstream &, Items &);
//void change();

int main()
{
	Items call;
	int option;

	fstream dataFile;//("inventory.dat", ios::out | ios::binary);
	//fstream dataFile("inventory.dat", ios::in | ios::binary);
	//fstream dataFile("inventory.dat", ios::out | ios::in | ios::binary);	// ::in, won't allow program to create a blank .dat file on its own
	//Items record = {" ", 0, 0, 0, " "};
	//dataFile.write(reinterpret_cast<char *>(&record),sizeof(record)); //writes blank record

	do
	{
		options();
		cout << "Your selection: ";
		cin >> option;
		cout << endl;

		switch (option)
		{
		case 1:
			dataFile.open("inventory.dat", ios::out | ios::binary | ios::app);
			addNew(dataFile, call);
			dataFile.close();
			break;
		case 2:
			dataFile.open("inventory.dat", ios::in | ios::binary);
			if(!fileExists("inventory.dat"))
			{
				cout << "File is not opened.\n";
				system("pause");
				return 0;
			}
			
			display(dataFile, call);
			dataFile.close();
			break;
		case 4:
			allContent(dataFile);
			break;
		case 3:
			//change();
			break;
		}


	} while (option > 0  && option < 5);

	cout << "\nBye-bye.\n";

	dataFile.close();

	system("pause");
	return 0;
}

void options()
{
	cout << "\nPress 1, to add a new record.\n";
	cout << "Press 2, to display current records.\n";
	cout << "Press 3, to change a record.\n";
	cout << "Press 4, to view all contents.\n";
	cout << "Press 0, to quit.\n\n";
}


void addNew(fstream& dFile, Items &call)
{
	//fstream dFile2 ("Inventory.dat", ios::out | ios::binary);  
	//Items call;  



	cout << "Enter Description: "; 
	cin.ignore();				//must be executed atleast once to allow user input later.
	getline(cin, call.desc);	//use this instead of cin >>, so content after spaces can be recognized
	//cin.getline(call.desc);	//
	cout << "Quantity\t: ";
	cin >> call.quantity;
	cout << "Wholesale cost\t: "; 
	cin >> call.wholeCost;
	cout << "Retail cost\t: ";
	cin >> call.retailCost;
	cout << "Data added\t: "; 
	cin.ignore();
	getline(cin, call.dateAdded);

	cout << "Adding record to file...\n";  

	dFile.seekp(ios::end); 
	// first obtain size of the structure's string desc member vairable
	size_t sDescSize = call.desc.size();
	dFile.write(reinterpret_cast<char*>(&sDescSize), sizeof(size_t));
	// write actual string (descripton)
	dFile.write(call.desc.c_str(), sDescSize);

	// write out quantity member vairable
	dFile.write(reinterpret_cast<char*>(&call.quantity), sizeof(call.quantity));
	// write out wholeCost and retailCost
	dFile.write(reinterpret_cast<char*>(&call.wholeCost), sizeof(call.wholeCost));
	dFile.write(reinterpret_cast<char*>(&call.retailCost), sizeof(call.retailCost));

	// obtain size of the structure's string date member vairable
	size_t sDateSize = call.dateAdded.size();
	dFile.write(reinterpret_cast<char*>(&sDateSize), sizeof(size_t));
	// write actual string (date added)
	dFile.write(call.dateAdded.c_str(), sDateSize);


	// prevent new records from over-writing old records.
	/*dFile.seekp(ios::end); 
	dFile.write(reinterpret_cast<char *>(&call),sizeof(call));
	//dFile.write(reinterpret_cast<char *>(&call),sizeof(call));  

	cout << "size of record " << sizeof(call) << endl;*/

	dFile.close();	//I've placed this in case 1 within the do-while loop of int main.
}


bool readRecord(fstream & dFile, Items &call)
{
	size_t descSize;
	// Read the size of the string
	dFile.read(reinterpret_cast<char*>(&descSize), sizeof(size_t));
	// resize string to the correct size
	call.desc.resize(descSize);
	// read in the string
	dFile.read(&call.desc[0], descSize);
	
	// read the quantity, whole & retail cost.
	dFile.read(reinterpret_cast<char*>(&call.quantity), sizeof(call.quantity));
	dFile.read(reinterpret_cast<char*>(&call.wholeCost), sizeof(call.wholeCost));
	dFile.read(reinterpret_cast<char*>(&call.retailCost), sizeof(call.retailCost));

	size_t dateSize;
	// Read the size of the string
	dFile.read(reinterpret_cast<char*>(&dateSize), sizeof(size_t));
	// resize string to the correct size
	call.dateAdded.resize(dateSize);
	// read in the string
	dFile.read(&call.dateAdded[0], dateSize);

	return (dFile);
}


void display(fstream& dFile, Items & call)
{
	//int recNum;
	//cout << "Enter the item's record number to view: ";
	//cin >> recNum;

	 //Produces error message

	int i = 0;
	
	while (readRecord(dFile, call)) //!dFile . eof() ) 
	{
		
		cout << "Description\t: " << call.desc << endl;  
		cout << "Quantity\t: " << call.quantity << endl;  
		cout << "Wholesale cost\t: " << call.wholeCost << endl;  
		cout << "Retail cost\t: " << call.retailCost << endl;  
		cout << "Date\t\t: " << call.dateAdded << endl << endl;  
		i++;
	}

	cout << "total iter: " << i << endl;
 
}



void allContent(fstream& dFile)	//Display all/present contents at once
{
	Items call;

	//fstream dFile2("inventory.dat", ios::in | ios:: binary);
	// Now read and display ALL the records 
	dFile.read(reinterpret_cast<char *>(&call), sizeof(call));

	while ( ! dFile . eof() ) 
	{ 
		cout << "Description	: " << call.desc << endl;  
		cout << "Quantity		: " << call.quantity << endl;  
		cout << "Wholesale cost: " << call.wholeCost << endl;  
		cout << "Retail cost	: " << call.retailCost << endl;  
		cout << "Date			: " << call.dateAdded << endl;  
		dFile.read(reinterpret_cast<char *>(&call), sizeof (call) ) ; 
	} 

	dFile.close();
}




bool fileExists(string filename)
{
		fstream file(filename, ios::in | ios::binary);
		bool exist = true;

		if( !file.is_open()) 
		{
			exist = false;
		}

		file.close();
		return exist;
}

Attached image(s)

  • Attached Image

Was This Post Helpful? 0
  • +
  • -

#34 jimblumberg  Icon User is online

  • member icon


Reputation: 4133
  • View blog
  • Posts: 12,865
  • Joined: 25-December 09

Re: Structure record binary file, refuses to display contents.

Posted 29 September 2012 - 08:54 AM

Quote

@ Jim, so you're saying, I should implement some sort of if statement for my display function?

No, I'm saying implement some sort of if statement where you read the data.

Quote

You say I should check the stream state after the first read. A do while statement comes to mind...

Why would a do/while statement come to mind when you are talking about checking the stream state?

Jim
Was This Post Helpful? 0
  • +
  • -

#35 mgrex  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 188
  • Joined: 25-March 10

Re: Structure record binary file, refuses to display contents.

Posted 29 September 2012 - 05:03 PM

I did the following and the call stack still displays the same output, in that the while loop header (in display Function), and line 150 in readRecords are the problems

bool readRecord(fstream & dFile, Items &call)
{
	size_t descSize;
	// Read the size of the string
	dFile.read(reinterpret_cast<char*>(&descSize), sizeof(size_t));
	// resize string to the correct size
	call.desc.resize(descSize);
	
	if (!dFile.eof())
		// read in the string
		dFile.read(&call.desc[0], descSize);
	
	// read the quantity, whole & retail cost.
	dFile.read(reinterpret_cast<char*>(&call.quantity), sizeof(call.quantity));
	dFile.read(reinterpret_cast<char*>(&call.wholeCost), sizeof(call.wholeCost));
	dFile.read(reinterpret_cast<char*>(&call.retailCost), sizeof(call.retailCost));

	size_t dateSize;
	// Read the size of the string
	dFile.read(reinterpret_cast<char*>(&dateSize), sizeof(size_t));
	// resize string to the correct size
	call.dateAdded.resize(dateSize);
	
	if (!dFile.eof())
		// read in the string
		dFile.read(&call.dateAdded[0], dateSize);

	return (dFile);
}

Was This Post Helpful? 0
  • +
  • -

#36 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3616
  • View blog
  • Posts: 11,263
  • Joined: 05-May 12

Re: Structure record binary file, refuses to display contents.

Posted 29 September 2012 - 06:24 PM

If the read on line 5 fails, you need to not believe the data that was read into the descSize, and you need to stop reading the rest of the record.
Was This Post Helpful? 0
  • +
  • -

#37 mgrex  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 188
  • Joined: 25-March 10

Re: Structure record binary file, refuses to display contents.

Posted 29 September 2012 - 06:50 PM

Does know of a tutorial/similar code, for coming up with the proper syntax?

placing an if(!dFile.fail()) before line 5 didn't help neither; call stack still directs to line 8.

{
	if (!dFile.fail())
	{
	size_t descSize;
	// Read the size of the string
	dFile.read(reinterpret_cast<char*>(&descSize), sizeof(size_t));
	// resize string to the correct size
	call.desc.resize(descSize);
	
	// read in the string
	dFile.read(&call.desc[0], descSize);
	
	// read the quantity, whole & retail cost.
	dFile.read(reinterpret_cast<char*>(&call.quantity), sizeof(call.quantity));
	dFile.read(reinterpret_cast<char*>(&call.wholeCost), sizeof(call.wholeCost));
	dFile.read(reinterpret_cast<char*>(&call.retailCost), sizeof(call.retailCost));

	size_t dateSize;
	// Read the size of the string
	dFile.read(reinterpret_cast<char*>(&dateSize), sizeof(size_t));
	// resize string to the correct size
	call.dateAdded.resize(dateSize);
	// read in the string
	dFile.read(&call.dateAdded[0], dateSize);

	}

	return (dFile);
}

Was This Post Helpful? 0
  • +
  • -

#38 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3616
  • View blog
  • Posts: 11,263
  • Joined: 05-May 12

Re: Structure record binary file, refuses to display contents.

Posted 29 September 2012 - 07:08 PM

As mentioned before, the fail and end of file bits are only set after an attempt to read fails or hits the end of file. With your current code in post #37, your are testing before before the read.
Was This Post Helpful? 1
  • +
  • -

#39 mgrex  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 188
  • Joined: 25-March 10

Re: Structure record binary file, refuses to display contents.

Posted 30 September 2012 - 10:02 AM

Since there only 3 records to display, I added an additional condition to the while statement, to make the while loop iterate 3 times. The 3 records displayed successfully, and the selection menu was brought up.

The addition is in line 42 of following. Nothing was displayed in the call stack. The main problem with the following is that is isn't as dynamic as eof(). Note that even with the if statement within the while loop, all the records were able to display, as well the total iterations and menu.

bool readRecord(fstream & dFile, Items &call)
{

	size_t descSize;
	// Read the size of the string
	dFile.read(reinterpret_cast<char*>(&descSize), sizeof(size_t));
	// resize string to the correct size
	call.desc.resize(descSize);
	
	// read in the string
	dFile.read(&call.desc[0], descSize);
	
	// read the quantity, whole & retail cost.
	dFile.read(reinterpret_cast<char*>(&call.quantity), sizeof(call.quantity));
	dFile.read(reinterpret_cast<char*>(&call.wholeCost), sizeof(call.wholeCost));
	dFile.read(reinterpret_cast<char*>(&call.retailCost), sizeof(call.retailCost));

	size_t dateSize;
	// Read the size of the string
	dFile.read(reinterpret_cast<char*>(&dateSize), sizeof(size_t));
	// resize string to the correct size
	call.dateAdded.resize(dateSize);
	// read in the string
	dFile.read(&call.dateAdded[0], dateSize);

	

	return (dFile);
}


void display(fstream& dFile, Items & call)
{
	//int recNum;
	//cout << "Enter the item's record number to view: ";
	//cin >> recNum;

	 //Produces error message

	int i = 0;
	
	while (readRecord(dFile, call) && i < 3 ) //!dFile . eof() ) 
	{
		if (!dFile.fail())
		{
			cout << "Description\t: " << call.desc << endl;  
			cout << "Quantity\t: " << call.quantity << endl;  
			cout << "Wholesale cost\t: " << call.wholeCost << endl;  
			cout << "Retail cost\t: " << call.retailCost << endl;  
			cout << "Date\t\t: " << call.dateAdded << endl << endl;  
			i++;
		}
	}
	cout << "total iter: " << i << endl;
 
}


The user, jimblumberg, told I had to implement an if statement in the readRecord function.
Isn't there some sort of additional condition I can use on the while loop, other than 3? dFile.eof(), dFile.good(), do not work.

I did the following nested while statements, and it resulted in the same call stack error, due to line 13, and line 11 in the readRecord function, notice that i:

notice that I still had i < 3, didn't help, unlike the previous code which it did. "total iter" statement, didn't display, nor the menu.

void display(fstream& dFile, Items & call)
{
	//int recNum;
	//cout << "Enter the item's record number to view: ";
	//cin >> recNum;

	 //Produces error message

	int i = 0;
	
	while (!dFile.eof())
	{
		while (readRecord(dFile, call) && i < 3) //!dFile . eof() ) 
		{
			//if (!dFile.fail())
			//{
				cout << "Description\t: " << call.desc << endl;  
				cout << "Quantity\t: " << call.quantity << endl;  
				cout << "Wholesale cost\t: " << call.wholeCost << endl;  
				cout << "Retail cost\t: " << call.retailCost << endl;  
				cout << "Date\t\t: " << call.dateAdded << endl << endl;  
				i++;
			//}
		}
	}
	
	cout << "total iter: " << i << endl;
 
}



The following segnment, caused the program to crash.

bool readRecord(fstream & dFile, Items &call)
{

	size_t descSize;
	// Read the size of the string
	dFile.read(reinterpret_cast<char*>(&descSize), sizeof(size_t));
	// resize string to the correct size
	call.desc.resize(descSize);
	
	// read in the string
	if (!dFile.eof())
		dFile.read(&call.desc[0], descSize);
	
	// read the quantity, whole & retail cost.
	dFile.read(reinterpret_cast<char*>(&call.quantity), sizeof(call.quantity));
	dFile.read(reinterpret_cast<char*>(&call.wholeCost), sizeof(call.wholeCost));
	dFile.read(reinterpret_cast<char*>(&call.retailCost), sizeof(call.retailCost));

	size_t dateSize;
	// Read the size of the string
	dFile.read(reinterpret_cast<char*>(&dateSize), sizeof(size_t));
	// resize string to the correct size
	call.dateAdded.resize(dateSize);
	// read in the string
	
	if (!dFile.eof())
		dFile.read(&call.dateAdded[0], dateSize);
	

	return (dFile);
}


void display(fstream& dFile, Items & call)
{
	//int recNum;
	//cout << "Enter the item's record number to view: ";
	//cin >> recNum;

	 //Produces error message

	int i = 0;
	
	while (readRecord(dFile, call) && !dFile . eof() ) 
	{
		//if (!dFile.fail())
		//{
			cout << "Description\t: " << call.desc << endl;  
			cout << "Quantity\t: " << call.quantity << endl;  
			cout << "Wholesale cost\t: " << call.wholeCost << endl;  
			cout << "Retail cost\t: " << call.retailCost << endl;  
			cout << "Date\t\t: " << call.dateAdded << endl << endl;  
			i++;
		//}
	}
	cout << "total iter: " << i << endl;
 
}


No with the previous segment, changing while to: while (readRecord(dFile, call) && i < 3 ) , with the if statements of line 11 and line 26, the records successfully displayed without the program crashing.
Was This Post Helpful? 0
  • +
  • -

#40 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3616
  • View blog
  • Posts: 11,263
  • Joined: 05-May 12

Re: Structure record binary file, refuses to display contents.

Posted 30 September 2012 - 10:21 AM

This is what jimblumberg was trying to say in psuedo code:
bool ReadARecord(ifstream & infile, ...)
{
    size_t stringSize;

    read in stringSize from infile
    if (infile has error)
        return false;

    allocate space for a string using stringSize

    read in string from infile

    :

    return infile;
}



What you've been implementing has been:
bool ReadARecord(ifstream & infile, ...)
{
    size_t stringSize;

    read in stringSize from infile
    allocate space for a string using stringSize

    if (infile does not have an error)
        read in string from infile

    :

    return infile;
}



If the read from infile failed, you will have some random value in stringSize. In your code where you go ahead and allocate with that random value anyway, you are causing the failure in the memory allocator.
Was This Post Helpful? 1
  • +
  • -

  • (3 Pages)
  • +
  • 1
  • 2
  • 3