Hello. The problem with the following code is that when I read from a file after restarting the program and then try to display the contents, it goes into an endless loop. I hope that someone can point out the logical error hiding there.

#include <iostream>
#include <windows.h>
#include <fstream>

#include "link.h";

;using namespace std;

class qu
{
	qu * next,*front,*rear;
	int d;
	int age;
	string name;
public:
	qu() {
		next=0;
		front=rear=0;
	}
	~qu() {  }
	void push(int n, int ag, string nam)
	{
		qu *newptr=new qu;
		newptr->d=n;
		newptr->age=ag;
		newptr->name=nam;

		if(front==0)
		{
			front=rear=newptr;
		}
		else {
			newptr->next=0;
			rear->next=newptr;
			rear=newptr;
		}

	}
	int pop()
	{
		if(front==0)
		{
			return -1;
		}
		else
		{
			qu *newptr=this->front;
			front=front->next;
			int n=newptr->d;
			delete newptr;
			return n;
		}
	}

	void disp()
	{
		cout<<"|---------------------------------------|"<<endl;
		cout<<"|            Student Data               |"<<endl;
		cout<<"|=======================================|"<<endl;
		cout<<"|Admission Number:      "<<d<<"            |"<<endl;
		cout<<"|Student's Name:        "<<name<<"            |"<<endl;
		cout<<"|Student's Age:         "<<age<<"            |"<<endl;
		cout<<"|=======================================|"<<endl;
	}

	void traverse()
	{
		system("cls");
		qu * newptr=this->front;
		cout<<"Student Details:        "<<'\n';
		if(newptr!=0) {
		while(newptr!=0)
		{
			newptr->disp();
			newptr=newptr->next;
		}
		delete newptr;
		}
		else cout<<"qu Empty!\n";
		cont();
	}

	void SaveDat();
	void ReadDat();

};

void qu::SaveDat()
{
	fstream Dat;
	system("cls");
	qu * newptr=this->front;
	Dat.open("datat.txt",ios::out);
	if(Dat) {
	cout<<"Saving to file...\n\n";
	if(newptr!=0) {
	while(newptr!=0)
	{
		Dat.write((char *) newptr, sizeof(qu));
		newptr=newptr->next;
	}
	delete newptr;
	Dat.close();
	cout<<"Saved!\n";
	}
	else cout<<"Qu empty! Nothing to save!\n";
	}
	else cout<<"Error! Could not open file for write!\n";
	cont();
}

void qu::ReadDat()
{
	fstream Dat;
	system("cls");
	qu * newptr=new qu;
	Dat.open("datat.txt",ios::in|ios::beg);
	if(Dat.eof()) { cout<<"No Data in file!\n\n"; }
	else {
	while(!Dat.eof()) {
	Dat.read((char *)newptr, sizeof(qu));
	if(front==0)
	{
		front=rear=newptr;
	}
	else
	{
		newptr->next=0;
		rear->next=newptr;
		rear=newptr;
	}
	}
	Dat.close();
	cout<<"qu Read!\n";
	}
	cont();
}

void PrntBox();

void enterInQu(qu * mqu)
{
	int n,ag;
	string nam;
	char ch;
	do {
	cout<<"Enter D number of student:\t";
	cin>>n;
	cout<<"Enter age of student:\t";
	cin>>ag;
	cout<<"Enter name of student:\t";
	cin.ignore(1,'\n');
	getline(cin,nam);
	mqu->push(n,ag,nam);
	cout<<"Enter more elements?(y/n)\n";
	cin>>ch;
	}while(ch=='y'||ch=='Y');
}

void deleteFrmQu(qu *mqu)
{
	int n=1;                                //Identifier to show qu empty or full
	char ch='y';
	while(ch=='y'&&n!=-1)
	{
		n=mqu->pop();
		if(n!=-1)
		{
			cout<<"Student record with D-number "<<n<<" deleted!\n";
			cout<<"Want to delete more students?(y/n)\n";
			cin>>ch;
		}
		else{
			cout<<"Qu is empty! Nothing to remove!\n";
		}
	}
}

void menu()
{
	qu * MyQu=new qu;
	int choice;
	char ch;
	while(1) {
		system("cls");
		system("COLOR 2");
	PrntBox();
	cin>>choice;

	switch(choice)
	{
	case 1: enterInQu(MyQu);
		break;
	case 2: MyQu->traverse();
		break;
	case 3: deleteFrmQu(MyQu);
		break;
	case 4: MyQu->ReadDat();
		break;
	case 5:
		MyQu->SaveDat();
		break;
	case 6: cout<<"Exiting Program...\n Press any Key to continue\n";
		cin.ignore(1,'\n');
		cin.get();
		exit(0);
	}
	}
}

int main()
{
	cout<<"Program to make a queue database...\n";
	menu();

}

void PrntBox()
{
	cout<<"1.Enter Data\n2.View Data\n3.Delete Data\n4.Read From File\n5.Save to file\n6.Exit\n\t";

}

You run the program, select the option that will read the file, then the program closes and you re-open. You then select the option that will print the data that was previously read?

That won't work. In the first instance, the data is read into memory. All of that memory is cleaned up when the program exits. So when you start it again, it remembers nothing from its previous run.

What you should do is modify the menu function, so that after finishing one of the cases it asks you again which action you would like to take.
That way you don't exit the program, and all the data that was read is still there.

You should also check of course, before printing the data that it already has been read. If not, give an error that the user should first select the action to read the data.

Thanks for replying. What you said is already implemented in the program. Maybe you didn't read my post clearly; this is the what i do to create the issue:-
1.Insert data into the queue implemented as linked list
2.Save to file
3. close program(keep in mind that the file is saved and not deleted after program closes)
4.Start program
5.Read from file
6.View data
The 6th step causes infinite loop which means that either it didn't get saved right or wasn't read right. The reason i posted here is for help in getting the issue resolved.

Sorry, I didn't really look at your code and misunderstood your question.

Something goes very wrong in your read data function:

while(!Dat.eof()) {
	Dat.read((char *)newptr, sizeof(qu));

Before the while loop you allocate one new qu object, but in the while loop you constantly overwrite whats written at this pointer.

So you'll need to allocate a new qu* every time you read it from the file, and add that new pointer to your linked list.

I dont know if that solves your problem.

Sorry, I didn't really look at your code and misunderstood your question.

Something goes very wrong in your read data function:

while(!Dat.eof()) {
	Dat.read((char *)newptr, sizeof(qu));

Before the while loop you allocate one new qu object, but in the while loop you constantly overwrite whats written at this pointer.

So you'll need to allocate a new qu* every time you read it from the file, and add that new pointer to your linked list.

I dont know if that solves your problem.

Thank you so much! Stupid of me for doing that mistake...
But there's still a problem. If I restart the program and read from file now and then display all records, it shows a random record with random numbers at the end... Does this mean its storing an unwanted memory address contents in file too?
Thanks.

That's because of your while loop, think about it:

while( ! Dat.eof() ) {
 Dat.read( ... );
 // Use what was read
}

Let's say there are 4 valid data structures in the file.
So Dat.read() will be called 4 times successfully, but it will not set the eof() flag after the 4th call yet.
So your loop has an extra iteration, where Dat.read() is called and all it does is set the eof flag. When this happens you still treat it as if it's a 5th data entry.

So you need to check Dat.eof() after every Dat.read call, before using the result of Dat.read

That's because of your while loop, think about it:

while( ! Dat.eof() ) {
 Dat.read( ... );
 // Use what was read
}

Let's say there are 4 valid data structures in the file.
So Dat.read() will be called 4 times successfully, but it will not set the eof() flag after the 4th call yet.
So your loop has an extra iteration, where Dat.read() is called and all it does is set the eof flag. When this happens you still treat it as if it's a 5th data entry.

So you need to check Dat.eof() after every Dat.read call, before using the result of Dat.read

I know you're right but I can't understand how eof() works then.
I thought that after every read from the file the cursor was moved forward kind of like when I type on this page now(but read instead of write). And then, the eof() function checks if there is any other data in the file in front of cursor remaining. Isn't that how it works? If it is, then my loop's cursor in the file should've moved to the 5th position (according to your hypothesis) after the fourth data read and then eof() should have a TRUE result.
Sorry, I'm not trying to say I'm right(I know I'm wrong somewhere) but I want to understand this deeper.

Edited 5 Years Ago by AnkitPasi: n/a

Read carefully when the eofbit is set (http://www.cplusplus.com/reference/iostream/istream/read/):
"eofbit | The end of the source of characters is reached before n characters have been read. This also sets failbit."

In the 4th call, all 'n' bytes are read before the end of the source is reached, eventhough the file pointer is now at the end of the file. In the 5th call you request n bytes again, but the end is immediately reached so the eofbit is set.

Hope that makes sense

Read carefully when the eofbit is set (http://www.cplusplus.com/reference/iostream/istream/read/):
"eofbit | The end of the source of characters is reached before n characters have been read. This also sets failbit."

In the 4th call, all 'n' bytes are read before the end of the source is reached, eventhough the file pointer is now at the end of the file. In the 5th call you request n bytes again, but the end is immediately reached so the eofbit is set.

Hope that makes sense

Thanks for explaining. I got it. Now I want to be able to delete the file from within the program. I tried using remove("filename.txt") and it worked for 2-3 program runs but now it gives an access violation error and crashes the program. Any ideas?

Can you show us the exact code you have now?

#include <string>
#include <fstream>
#include <iostream>
using std::string;
using namespace std;


void cont()
{
	cout<<"Press any key to continue\n";
	cin.ignore(5,'\n');
	cin.get();
}
void spaces(int n)
{
	for(int i=1;i<=n;i++)
	{
		cout<<' ';
	}
}
int NoOfDigits(int n)
{
	int num=0;
	if(n<0) n=-n;
	while(n>0)
	{
		n/=10;
		++num;
	}
	return num;
}


class UserId                          //Used to authorize access to files
{
protected:
	int authorized;
	char User[100];
	char Pass[100];
	fstream Log1;
public:
	int Auth();
	char * EnterU();
	char * EnterP();
};

int UserId::Auth()
{
	authorized=0;
	Log1.open("Log",ios::in|ios::binary);
	char *tuser= new char[100];
	char* tpass=new char[100];
	int exists=0;
	if(!Log1.eof()) exists=1;
	switch(exists)
	{
	case 1: cout<<"Account exists. Please Login...\n";
		Log1>>User;
		Log1.ignore(1,' ');
		Log1>>Pass;
		strcpy(tuser,EnterU());
		strcpy(tpass,EnterP());
		if(strcmp(User,tuser)==0)
			if(strcmp(Pass,tpass)==0)
			{
				cout<<"Authorized!\n";
				authorized=1;
			}
			else{ cout<<"User ID or Password incorrect\n";
			authorized=0;
			}
		break;
	case 0: cout<<"\nNo Account exists!\n";
		strncpy(User,EnterU(),100);
		strncpy(Pass,EnterP(),100);
		Log1.open("Log",ios::out|ios::binary);
		Log1<<User<<' '<<Pass;
		authorized=1;
	}
	return authorized;
}

char * EnterU()
{
	char tuser[100];
	cout<<"\nEnter User ID: ";
	cin.getline(tuser,100);
	return tuser;
}

char * EnterP()
{
	char tpass[100]={0}, ch,a[100];
	int i=0;
	while(ch!='\n'&&i<100)
	{
		if(ch==13) break;
		else if(ch==8) {
			if(i!=0)
			--i;
		}
		else {
			tpass[i]=ch;
			a[i++]='*';
		}
		system("cls");
		cout<<"\nPassword :";
		for(int j=0;j<i;j++)
		{
			cout<<a[j];
		}
	}
	tpass[i]='\0';
	return tpass;
}





//***********************************************************   class qu *********************************************************//

class qu:public UserId
{
	qu * next,*front,*rear;
	int d;
	int age;
	string name;
public:
	qu() {
		next=0;
		front=rear=0;
	}
	~qu() {  }
	void push(int n, int ag, string nam)
	{
		qu *newptr=new qu;
		newptr->d=n;
		newptr->age=ag;
		newptr->name=nam;

		if(front==0)
		{
			front=rear=newptr;
		}
		else {
			newptr->next=0;
			rear->next=newptr;
			rear=newptr;
		}

	}
	int pop()
	{
		if(front==0)
		{
			return -1;
		}
		else
		{
			qu *newptr=this->front;
			front=front->next;
			int n=newptr->d;
			delete newptr;
			return n;
		}
	}

	void disp()
	{
		const int Length_d=NoOfDigits(d);
		const int Length_age=NoOfDigits(age);
		const int Length_name=name.size();
		cout<<"|---------------------------------------|"<<endl;
		cout<<"|            Student Data               |"<<endl;
		cout<<"|=======================================|"<<endl;
		cout<<"|Admission Number:      "<<d;                   
		spaces(16-Length_d);
		cout<<'|'<<endl;
		cout<<"|Student's Name:        "<<name;
		spaces(16-Length_name);
		cout<<'|'<<endl;
		cout<<"|Student's Age:         "<<age;
		spaces(16-Length_age);
		cout<<'|'<<endl;
		cout<<"|=======================================|"<<endl;
	}

	void traverse()
	{
		system("cls");
		qu * newptr=this->front;
		cout<<"Student Details:        "<<'\n';
		if(newptr==0) cout<<"qu Empty!\n";
		else while(newptr!=0)
		{
			newptr->disp();
			newptr=newptr->next;
		} 
		cont();
	}

	void SaveDat();
	void ReadDat();
	void DelFile();

};

void qu::SaveDat()
{
	fstream Dat;
	system("cls");
	qu * newptr=this->front;
	Dat.open("datat.txt",ios::out|ios::trunc);
	if(Dat) {
	cout<<"Saving to file...\n\n";
	if(newptr!=0) {
	while(newptr!=0)
	{
		Dat.write((char *) newptr, sizeof(qu));
		newptr=newptr->next;
	}
	delete newptr;
	Dat.close();
	cout<<"Saved!\n";
	}
	else cout<<"Qu empty! Nothing to save!\n";
	}
	else cout<<"Error! Could not open file for write!\n";
	cont();
}

void qu::ReadDat()
{
	fstream Dat;
	system("cls");
	Dat.open("datat.txt",ios::in|ios::beg);
	if(!Dat) { cout<<"No Data in file!\n\n"; }
	else while(!Dat.eof()) {
	qu * newptr=new qu;
	Dat.read((char *)newptr, sizeof(qu));
	if(!Dat.eof()) {
	if(front==0)
	{
		front=rear=newptr;
	}
	else
	{
		newptr->next=0;
		rear->next=newptr;
		rear=newptr;
	}

	}

	}
	Dat.close();
	cout<<"qu Read!\n";
	cont();
}

void qu::DelFile()
{
	if(remove("datat.txt")!=0) perror("Error deleting File ");
	else cout<<"File Successfully deleted!\n";
	cont();
}

void PrntBox();

void enterInQu(qu * mqu)
{
	int n,ag;
	string nam;
	char ch;
	do {
	cout<<"Enter D number of student:\t";
	cin>>n;
	cout<<"Enter age of student:\t";
	cin>>ag;
	cout<<"Enter name of student:\t";
	cin.ignore(1,'\n');
	getline(cin,nam);
	mqu->push(n,ag,nam);
	cout<<"Enter more elements?(y/n)\n";
	cin>>ch;
	}while(ch=='y'||ch=='Y');
}

void deleteFrmQu(qu *mqu)
{
	int n=1;                                //Identifier to show qu empty or full
	char ch='y';
	while(ch=='y'&&n!=-1)
	{
		n=mqu->pop();
		if(n!=-1)
		{
			cout<<"Student record with D-number "<<n<<" deleted!\n";
			cout<<"Want to delete more students?(y/n)\n";
			cin>>ch;
		}
		else{
			cout<<"Qu is empty! Nothing to remove!\n";
		}
	}
}

void menu()
{
	qu * MyQu=new qu;
	int choice;
	char ch;
	while(1) {
			system("cls");
		if(MyQu->Auth()) {
	
		system("COLOR 2");
	PrntBox();
	cin>>choice;

	switch(choice)
	{
	case 1: enterInQu(MyQu);
		break;
	case 2: MyQu->traverse();
		break;
	case 3: deleteFrmQu(MyQu);
		break;
	case 4: MyQu->ReadDat();
		break;
	case 5:
		MyQu->SaveDat();
		break;
	case 6: MyQu->DelFile();
		break;
	case 7: cout<<"Exiting Program...\n";
		cont();
		exit(0);
	}
	}        }
}

int main()
{
	cout<<"Program to make a queue database...\n";
	menu();
	return 0;

}

void PrntBox()
{
	cout<<"1.Enter Data\n2.View Data\n3.Delete Data\n4.Read From File\n5.Save to file\n6.Delete File\n7.Exit\n";

}

Another issue:
1>main.obj : error LNK2019: unresolved external symbol "public: char * __thiscall UserId::EnterP(void)" (?EnterP@UserId@@QAEPADXZ) referenced in function "public: int __thiscall UserId::Auth(void)" (?Auth@UserId@@QAEHXZ)
1>main.obj : error LNK2019: unresolved external symbol "public: char * __thiscall UserId::EnterU(void)" (?EnterU@UserId@@QAEPADXZ) referenced in function "public: int __thiscall UserId::Auth(void)" (?Auth@UserId@@QAEHXZ)
1>d:\docs\visual studio 2010\Projects\POD\Debug\POD.exe : fatal error LNK1120: 2 unresolved externals

You declared the EnterP and EnterU functions as part of a class, however in the implementation you forgot the classname:: infront of the function name.

I haven't really looked at your 'remove' problem yet.. are you sure all instances to the stream object are closed before you call remove?

Edited 5 Years Ago by thelamb: n/a

Any ideas on how to advance my c++ knowledge(which is very basic, i know)? I will have around 2-3 months off school after the 12th grade this year and want to learn more and start making "real" programs. Also, what platform should I make apps for?(windows, linux, os x)

The platform will not matter much if your goal is to learn C++.
The way I learned is simply by doing a larger project, and learning on the way (I had the luxury that someone else proposed a fairly big project).

The project I started with ran for about 2 years after which I completely rewrote it (was a server application).

Unfortunately, my creativity for project-ideas is non-existing - so come up with something (it doesnt even need to be useful) and just start, really think about the design, create half of it and then realize that it's totally wrong and do it better. Repeat.

Of course if you have questions about your design, post it here ;)

You might also want to get a good book (there are links in a sticky post). I like to have 'The C++ Programming Language' nearby as a reference.

Edited 5 Years Ago by thelamb: n/a

The platform will not matter much if your goal is to learn C++.
The way I learned is simply by doing a larger project, and learning on the way (I had the luxury that someone else proposed a fairly big project).

The project I started with ran for about 2 years after which I completely rewrote it (was a server application).

Unfortunately, my creativity for project-ideas is non-existing - so come up with something (it doesnt even need to be useful) and just start, really think about the design, create half of it and then realize that it's totally wrong and do it better. Repeat.

Of course if you have questions about your design, post it here ;)

You might also want to get a good book (there are links in a sticky post). I like to have 'The C++ Programming Language' nearby as a reference.

Thanks for your reply. I normally just google for reference. But, I do have SAMs teach yourself c++ lying somewhere. Did the application you made run in a gui or a cli? I don't know GUI programming :'(

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