Infinite loop reading file into array - c++

I have an infinite loop while trying to read a file. File is saved from user input, then it is to be read, finally, displayed using a separate function.
Here is my read function. The loop is not finding the eof(); from the file. I can't see what the issue is. No compiler errors.
void read(HouseholdItems items[AMOUNT], fstream& myFile, fstream& yourFile)
{
myFile.open("insured.dat", ios::in | ios::binary); // Open myFile
yourFile.open("uninsured.dat", ios::in | ios::binary); // Open yourFile
for(int i = 0; i < AMOUNT; i++)
{
myFile.read(reinterpret_cast <char*>(&items[i]),sizeof(&items[i]));
yourFile.read(reinterpret_cast <char*>(&items[i]),sizeof(&items[i]));
for(i = 0; i < AMOUNT; i++)
{
while (myFile)
{
cout << "description: ";
cout << items[i].description << endl;
cout << "quantity: ";
cout << items[i].quantity << endl;
cout << "price: ";
cout << items[i].price << endl;
cout << "insured: ";
cout << items[i].insured << endl;
}
}
}
myFile.close();
yourFile.close();
}

The following loop can never end : no modification is made to myFile inside its body :
while (myFile)
{
cout << "description: ";
cout << items[i].description << endl;
cout << "quantity: ";
cout << items[i].quantity << endl;
cout << "price: ";
cout << items[i].price << endl;
cout << "insured: ";
cout << items[i].insured << endl;
}
You have to read the file inside the while loop for it to end.
Besides, you most likely have a variable name conflict: you have two for loops that use the same variable i ; which is presumably not what you want.

Your problem is while(myFile), since nothing about myFile changes in that loop. It isn't clear what it is you mean for that loop to accomplish, so I can't say what to replace it with. (It does seem problematic that you have nested for loops, but don't seem to have a table of data.)

The answers by #ScottHunter and #Ekelog already answer the real problem. The following are peripheral problems.
These lines are not right:
myFile.read(reinterpret_cast <char*>(&items[i]),sizeof(&items[i]));
yourFile.read(reinterpret_cast <char*>(&items[i]),sizeof(&items[i]));
You need to use:
myFile.read(reinterpret_cast <char*>(&items[i]),sizeof(items[i]));
// ^^ Drop the &
yourFile.read(reinterpret_cast <char*>(&items[i]),sizeof(items[i]));
// ^^ Drop the &

try this in while
while (!myFile.eof())
{
cout << "description: ";
cout << items[i].description << endl;
cout << "quantity: ";
cout << items[i].quantity << endl;
cout << "price: ";
cout << items[i].price << endl;
cout << "insured: ";
cout << items[i].insured << endl;
}

See inline comments:
void read(HouseholdItems items[AMOUNT], fstream& myFile, fstream& yourFile)
{
// since you open and close those files here, you probably
// want to declare them here instead as a function parameter
myFile.open("insured.dat", ios::in | ios::binary); // Open myFile
yourFile.open("uninsured.dat", ios::in | ios::binary); // Open yourFile
// test in the loop
for(int i = 0; i < AMOUNT && myFile && yourFile; i++)
{
// these two reads do not make sense, the second one
// will overwrite the data just read by the first one...
// maybe you meant that one of the file might be smaller?
// or maybe to compare the results in some ways (in which
// case you need two arrays)
myFile.read(reinterpret_cast <char*>(&items[i]),sizeof(items[i]));
yourFile.read(reinterpret_cast <char*>(&items[i]),sizeof(items[i]));
// write current result
cout << "description: ";
cout << items[i].description << endl;
cout << "quantity: ";
cout << items[i].quantity << endl;
cout << "price: ";
cout << items[i].price << endl;
cout << "insured: ";
cout << items[i].insured << endl;
}
myFile.close();
yourFile.close();
}
As a side note:
Your second for() loop reused the i variable which means it would not work at all as expected.
As pointed out by others the sizeof() was wrong, you could also use sizeof(items[0]) since all items are equal in size.
As mentioned by SamIAm, the while() was blocking because the file was not being read so the EOF never actually reached in the file.
As shown in the comments, the file objects should probably be defined in the function instead of outside and passed in as references.

Related

Changing the first line of file and going to the last without losing data c++

I'm working on a school project for C++ with involves on working with polimorfism, dynamic objects, heritage. My project consists on an main.cpp with will run a loop with options for the user to select. I will be storing some data in a file, the data will be appended so I don't loose the data that was already in the file, but my file works like the following example:
2
Data;12;21;0
Data2s;22;61;7
This is what I want to happen:
3
Data;12;21;0
Data2s;22;61;7
Data3s;8;2;9
What I'm attempting to do is, I have to change the first line to the next variable number, and I can't loose the data under it.
After I change the line, I will go to the end of the file (after numb 7) so I can add another line of data.
attempt 1:
void Empresa::save_data(){
ofstream arquivoE;
arquivoE.open("data.txt", ios::app);
if (temp > 0){
arquivoE.seekp(0) << num_func;
arquivoE.seekp(0, ios_base::end);
arquivoE << endl;
}else{
arquivoE << num_func << endl;
}
for (int i = temp; i < num_func; i++)
{
arquivoE << func[i]->getNome() << ";" << func[i]->getEmissao() << ";" << func[i]->getSalario() << ";" << func[i]->last_field() << endl;
}
cout << " Sucesso ao gravar arquivo!" << endl;
arquivoE.close();
}
attempt 2:
void Empresa::save_data(){
ofstream arquivoE;
arquivoE.open("data.txt", ios::out);
arquivoE.seekp(0, ios::beg) << num_func;
arquivoE.seekp(0, ios::end);
arquivoE << endl;
for (int i = temp; i < num_func; i++)
{
arquivoE << func[i]->getNome() << ";" << func[i]->getEmissao() << ";" << func[i]->getSalario() << ";" << func[i]->last_field() << endl;
}
cout << " Sucesso ao gravar arquivo!" << endl;
arquivoE.close();
}
num_func is the the variable from the first line, which I need to change
Temp variable is just to keep track of where to add the line
This is the data line:
arquivoE << func[i]->getNome() << ";" << func[i]->getEmissao() << ";" << func[i]->getSalario() << ";" << func[i]->last_field() << endl;

How to add multiple lines to a file in C++?

I am new to C++ and write a little todo list on the console.
I am only able to add one line to a text file but when I try to add more it just won't appear on my text file.
Please take a look what I am doing wrong
//output-file stream
ofstream file;
file.open("output.txt", std::ios_base::app); //append
bool isRunning = true;
while (isRunning) {
cout << "Please select an action:" << endl;
cout << "add - adding tasks to the list" << endl;
cout << "del - deleting tasks to the list" << endl;
cout << "list - show the list" << endl;
cout << "x - to exit program" << endl;
string input;
cin >> input;
string addedTask;
if (input == "add") {
cout << "Please enter a task you like to add: " << endl;
cin.ignore();
if (std::getline(std::cin, addedTask)) {
file << addedTask << "\n";
}
else {
cout << "Failed to read line" << endl;
}
}
Why can I only add one string line? I still can't figure out the problem or am I missing something?
Did you try replacing your
file << addedTask << "\n";
by
file << addedTask << endl;
I think it should work (for me it's working)

Reading/ Writing from/to a file

I am working on an OOP project and I need to write into a file and I faced a problem that each time I do it the file is over written with only one object. How can I make it to write data of all the objects? I tried this but didnt work.
virtual void save(ofstream outfile) = 0;`// the base class
void AND2::save(ofstream outf) //derived
{
outf.open("test.txt");
outf << Component::getype() << " ";
outf<< Component::getid() << " ";
outf << Component:: graphicsinfomration().x1 << " ";
outf<< Component::graphicsinfomration().x2 << " ";
outf << graphicsinfomration().y1 << " ";
outf << graphicsinfomration().y2 << " ";
outf << endl;
outf.close();
}
else
{
ofstream outf;
for (int i = 0; i < (pApp->getcompcount()); i++)
{
//ask user to enter text name
c[i]->save( outf);
}
pOut->ClearStatusBar();
}
Because you're opening the file again and again you overwrite the contents again and again.
You probably want to open the stream outside the for loop once and pass it by reference.

Issue with saving an edited infile to an outfile in c++

Im having an issue with the last section of coding on here. The // Copy files from infile to outfile. The program transfers my infile which is simply a an 8 digit number , 20392207,splits it up into individual digits using the .at method; and is supposed to save that output to an outfile. I cant figure out how to save the output to the outfile. Any advice?
infile looks as follows
20392207
program output looks like this
The input number :20392207
The number 1:2
The number 2:0
The number 3:3
The number 4:9
The number 5:2
The number 6:2
The number 7:0
The number 8:7
outfile is supposed to look like the program out put, but instead just looks like an exact copy of the infile.
#include<iostream>
#include<fstream>
#include<cstdlib>
#include<string>
#include<cmath>
using namespace std;
int main()
{
string ifilename, ofilename, line, line2;
ifstream inFile, checkOutFile;
ofstream outFile;
char response;
int i;
// Input file
cout << "Please enter the name of the file you wish to open : ";
cin >> ifilename;
inFile.open(ifilename.c_str());
if (inFile.fail())
{
cout << "The file " << ifilename << " was not successfully opened." << endl;
cout << "Please check the path and name of the file. " << endl;
exit(1);
}
else
{
cout << "The file is successfully opened." << endl;
}
// Output file
cout << "Please enter the name of the file you wish to write : ";
cin >> ofilename;
checkOutFile.open(ofilename.c_str());
if (!checkOutFile.fail())
{
cout << "A file " << ofilename << " exists.\nDo you want to continue and overwrite it? (y/n) : ";
cin >> response;
if (tolower(response) == 'n')
{
cout << "The existing file will not be overwritten. " << endl;
exit(1);
}
}
outFile.open(ofilename.c_str());
if (outFile.fail())
{
cout << "The file " << ofilename << " was not successfully opened." << endl;
cout << "Please check the path and name of the file. " << endl;
exit(1);
}
else
{
cout << "The file is successfully opened." << endl;
}
// Copy file contents from inFile to outFile
while (getline(inFile, line))
{
cout << "The input number :" << line << endl;
for (i = 0; i < 8; i++)
{
cout << "The number " << i + 1 << ":";
cout << line.at(i);
cout << endl;
}
outFile << line << endl;
}
// Close files
inFile.close();
outFile.close();
} // main
Here we can see that outFile is only written to outside of the while loop:
while (getline(inFile, line))
{
cout << "The input number :" << line << endl;
for (i = 0; i < 8; i++)
{
cout << "The number " << i + 1 << ":";
cout << line.at(i);
cout << endl;
}
}
outFile << line << endl;
It has no chance of containing the same output as the console
Solution: Write inside the loop the same stuff that was written to the console:
while (getline(inFile, line))
{
cout << "The input number :" << line << endl;
outFile << "The input number :" << line << endl;
blah blah blah
}
But this looks like crap and a function makes like a better solution by eliminating duplication and upping re-usability.
void output(std::ostream & out,
const std::string & line)
{
out << "The input number :" << line << endl;
for (int i = 0; i < 8; i++)
{
out << "The number " << i + 1 << ":";
out << line.at(i);
out << endl;
}
}
and called:
while (getline(inFile, line))
{
output(cout, line);
output(outFile, line);
}
You need to write to outFile inside the while(getline(inFile, line)) loop.
[edit] see user4581301's answer for a more thorough treatment.

C++ doesn't convert string from data

I want to write a little program which should be used in supermarkets. everything is fictitious and it's only for learning purposes.
However, The tool generate a new data for every new article. in the data there are 2 lines, the name and the prise.
The data is named as the article number of the product. So the user enter a articlenumber and the tool looks for a data with this number, if it found it, it reads the 2 lines and initiates the variables.
But for some reasons it does not convert and copy the strings correctly.
here is the part which loads the data.
int ware::load()
{
string inhalt;
cout << "please insert article number" << endl;
cin >> articlenumber;
productname.open(articlenumber, ios::in);
if (!productname.is_open())
{
cout << "can't find the product." << endl;
return 1;
}
if (productname.is_open())
{
while (!productname.eof())
{
getline(productname, inhalt);
strcpy(name,inhalt.c_str());
getline(productname, inhalt);
price = atoi (inhalt.c_str());
cout << inhalt << endl;
}
warenname.close();
}
cout << endl << endl <<
"number: " << inhalt <<
" preis: " << price <<
" name: " << name <<
endl << endl; //this is a test and will be deleted in the final
}
hope you can help me!
Here is the class:
class ware{
private:
char articlenumber[9];
char name[20];
int price;
fstream warennamefstream;
ifstream warenname;
public:
void newarticle(); //this to make a new product.
void scan(); //this to 'scan' a product (entering the article number ;D)
void output(); //later to output a bill
int load(); //load the datas.
};
hope everything is fine now.
First, you have a using namespace std; somewhere in your code. This occasionally leads to subtle bugs. Delete it. ( Using std Namespace )
int ware::load()
{
string inhalt;
cout << "please insert article number" << endl;
cin >> articlenumber;
The type of articlenumber is incorrect. Declare it std::string, not char[]. ( What is a buffer overflow and how do I cause one? )
productname.open(articlenumber, ios::in);
There is no reason to have an ifstream lying around waiting to be used. Also, there is no point in providing ios::in -- it is the default. Just use the one-argument form of the ifstream constructor.
if (!productname.is_open())
{
cout << "can't find the product." << endl;
return 1;
}
Don't bother checking to see if the file opened. Your users don't care if the file was present or not, they care whether the file was present AND you retrieved the essential data.
if (productname.is_open())
{
while (!productname.eof())
{
getline(productname, inhalt);
strcpy(name,inhalt.c_str());
getline(productname, inhalt);
price = atoi (inhalt.c_str());
cout << inhalt << endl;
}
warenname.close();
}
This loop is just wrong.
Never invoke eof(). It doesn't do what you think it does, and will cause bugs.
Why is this a loop? Aren't there only two lines in the file?
There is no point in calling close. Just let the file close when the istream goes out of scope.
Why is warename different than productname?
Don't store your data in char[]. This is the 21st century. Use std::string.
.
cout << endl << endl <<
"number: " << inhalt <<
" preis: " << price <<
" name: " << name <<
endl << endl; //this is a test and will be deleted in the final
Never use endl when you mean to say '\n'. Each of those endl manipulators invokes flush, which can be very expensive. ( What is the C++ iostream endl fiasco? )
You forgot to return a value.
Try this instead:
int ware::load()
{
// This declaration should be local
std::string articlenumber;
cout << "please insert article number" << endl;
cin >> articlenumber;
// This declaration should be local
std::ifstream productname(articlenumber.c_str());
// These declarations can be class members:
std::string name;
int price;
std::string number;
if(getline(productname, name) &&
productname>>price &&
productname>>number)
{
cout << "\n\n" <<
"number: " number <<
" preis: " << price <<
" name: " << name <<
"\n\n"; //this is a test and will be deleted in the final
return 0;
} else {
cout << "can't find the product." << endl;
return 1;
}
}