This question already has answers here:
eof problem c++
(3 answers)
Closed 8 years ago.
I have a function for deleting data from a text file.
I'm having problems when valid input is entered:
if I enter bad input, it only executes the else part, as expected
if I enter valid input, it executes both the if and the else part.
Here is my code:
void Member::processTransaction()
{
fstream f;
f.open("Member.txt",ios::in|ios::out);
int x = 0, y = 0, z = 0;
while (!f.eof())
{
f >> idList[x] >> nameList[y];
if (id == idList[x])
{
cout << idList[x] << "\t" << nameList[x] << endl;
cout << "Do you want to delete the entry (Y/N) : " << endl;
char deleteEntry = getche();
if(deleteEntry=='Y'||deleteEntry=='y')
deleteInformation();
f.close();
}
else
{
cout << "No Matches Found!";
}
}
}
in the output. If I enter True, it executes and displays "No Matches Found".
If I enter false, it only displays "No Matches Found" and its fine.
while(!f.eof()){ is almost always a mistake. This case is no exception.
eof means you tried to read something previously, and it failed due to end of file. It's false if you have read the whole file exactly, and it's false if you close the file before trying to read past the end as you do in this example. And it's false if the stream is in an error state for another reason.
Instead , change to while (f >> idList[x] >> nameList[y]), and use break; if you want to exit the loop for some other reason than this read failing.
void Member::processTransaction() {
fstream f;
f.open("Member.txt", ios::in | ios::out);
int x = 0, y = 0, z = 0;
bool found = false; // found or not?
// search the file now.
while(!f.eof() && !found) {
f >> idList[x] >> nameList[y];
if(id != idList[x]) {
continue;
}
cout << idList[x] << "\t" << nameList[x] << endl;
cout << "Do you want to delete the entry (Y/N) : " << endl;
char deleteEntry = getche();
if(deleteEntry == 'Y' || deleteEntry == 'y') {
deleteInformation();
}
found = true;
}
f.close(); // close here
// not found only after you're done searching.
if(!found) {
cout << "No Matches Found!";
}
}
Your code is bad. My code is just less bad. Your entire way of doing this is flawed. But this is the right wrong way to do it.
Related
This question already has answers here:
Read file line by line using ifstream in C++
(8 answers)
Closed 1 year ago.
I am trying to get the user to key in data and store them inside a vector so when -1 is being entered it will break the entire loop and start displaying the vector. However it is currently not working even if -1 has been entered the loop will still continue to go on.
void cargo::addCargo(vector<cargo> &userCargo)
{
fstream file;
file.open("cargo.txt", ios::out | ios::app);
int i = 0;
bool checker = true;
cargo newCargo;
while (checker == true)
{
cout << "Enter id" << endl;
if (cin.peek() == '-1')
{
checker = false;
cout << "Hello";
}
else
{
cin >> idCon;
newCargo.setId(idCon);
}
cout << "Enter Destination Country" << endl;
if (cin.peek() == '-1')
{
checker = false;
}
else
{
cin >> destCountryCon;
newCargo.setDestCountry(destCountryCon);
}
cout << "Enter Time" << endl;
if (cin.peek() == '-1')
{
checker = false;
}
else
{
cin >> timeCon;
newCargo.setTime(timeCon);
newCargo.setIndex(i + 1);
userCargo.push_back(newCargo);
}
cout << endl;
i++;
}
//loop to display the entire vector
displayCargo(userCargo);
}
You are code is not self-contained so I can't fix it for you. The pragmatic answer is break or continue with a flag like checker. peek() looks at the next character and when the user enters "-1" it will return '-' and not the multi-character constant '-1'. Alternative, user can press ctrl-d to trigger eof. If you want to use "-1" (who came up with that terrible ux?), read that as a string or int.
Problem Sample Run
Problem Description (1)
Problem Description (2)
The link above is an image of what the program should do once reading in a text file and outputting it correctly to another file. The two other links are descriptions of the problem itself. My problem is that while most of the logic works, when it comes to printing it out, it skips the first number in the input file. For example, if the input file was:
1 10000
2 5000
3 150000
Right now the output in the file prints:
Store 2: *
Store 3: ***
Again, the image provides a better example of what is to happen. The code should work for any text file given, no matter for the order of the numbers: (ex: 50 10000, 5 5000, so on).
I am not sure why this happening. I'm attaching my code for reference below. I would like to apologize in advance for the lack of comments right now, I'm trying to fix the error first. I have narrowed the error down to the while loop in the main function however. Second, I'm somewhat of a beginner, so please excuse any silly mistakes I've made or if I did things in a more inefficient way. Another note is that I can't change the signatures for the functions, and I have to check the values if they are valid in the readFile() function. I also cannot use arrays, or the pause command, or break and continue. Third, I am pretty new to stack overflow so please do excuse any errors I make. Thank you!
As of now, the code that is commented out, is code I don't plan to use, but if there is a way to achieve the goal using that code and staying within the guidelines, please do let me know. This error is quite a frustrating one! Also, I do have some more error to fix afterwards, but those are minor ones I can fix later. I want to fix this error first. Thank you!
#include <iostream>
#include <iomanip>
#include <cmath>
#include <fstream>
using namespace std;
bool readFile(ifstream&, long long int&, unsigned int&);
void display(ofstream&, long long int, unsigned int);
int main()
{
ifstream inputFile;
ofstream outputFile;
string fileName;
long long int salesData;
unsigned int storeNumber;
cout << "Enter input file name" << endl;
cin >> fileName;
inputFile.open(fileName);
bool fileRead = readFile(inputFile, salesData, storeNumber);
if(fileRead)//inputFile >> storeNumber >> salesData)
{
outputFile.open("saleschart.txt");
outputFile << "SALES BAR CHART" << endl;
outputFile << "(Each * equals 5,000 dollars)" << endl;
while(inputFile >> storeNumber >> salesData)
{
display(outputFile, salesData, storeNumber);
/*
if(storeNumber < 1 || storeNumber > 99)
{
cout << "The store number " << storeNumber << " is not valid" << endl;
}
if(salesData < 0)
{
cout << "The sales value for store " << storeNumber << " is negative" << endl;
}
*/
}
inputFile.close();
outputFile.close();
}
return 0;
/*
while(inputFile >> storeNumber >> salesData)
{
int counter = 1;
for(int i = 1; i <= counter; i++)
{
counter++;
bool fileRead = readFile(inputFile, salesData, storeNumber);
if(fileRead)
{
outputFile.open("saleschart.txt");
outputFile << "SALES BAR CHART" << endl;
outputFile << "(Each * equals 5,000 dollars)" << endl;
display(outputFile, salesData, storeNumber);
}
}
*/
}
bool readFile(ifstream& inputFile, long long int& salesData, unsigned int& storeNumber)
{
if(inputFile)
{
inputFile >> storeNumber >> salesData;
if(storeNumber == NULL)
{
cout << "The file was empty" << endl;
return false;
}
if(storeNumber < 1 || storeNumber > 99)
cout << "The store number " << storeNumber << " is not valid" << endl;
if(salesData < 0)
cout << "The sales value for store " << storeNumber << " is negative" << endl;
else
return true;
}
else
{
cout << "File \"sales.txt\" could not be opened" << endl;
return false;
}
return false;
/*
if(inputFile.eof())
return false;
else
{
inputFile >> storeNumber >> salesData;
return true;
}
*/
}
void display(ofstream& outputFile, long long int salesData, unsigned int storeNumber)
{
outputFile << left << setw(6) << "Store" << right << setw(2) << storeNumber << ": ";
cout<<storeNumber; //DEBUG
for(int i = 0; i < (salesData/5000); i++)
{
outputFile << left << "*";
}
outputFile << endl;
}
It's skipping the first numbers because you read them (and the don't save them) in the function readFile. It's got nothing to do with your while loop which is completely correct. But you can't read the same numbers twice, and you have already read the first numbers by the time you get to your while loop.
Not sure what you are expecting from the function readFile, it looks like you tried to read the file in a separate function but then abandoned it. If you just delete the readFile function your code should work.
OK reading your question again I see that are required to use the readFile function. If that is the case then the correct thing to do is delete the current contents of the readFile function and move the while loop into the readFile function.
You have a few problems, the main is that the readFile function reads the first two values, and then you discard the data it has read.
This discarded data will never be written to the output file.
Also in the readFile function you have the comparison storeNumber == NULL which might be a check if the input failed, but that's not how to do that.
First of all because C++ doesn't have null values, NULL is an old C-compatibility constant for a null pointer.
Secondly, you already have the correct check in the loop where you read the remaining data, where you use the whole input expression inputFile >> storeNumber >> salesData as the condition.
Now to put it all together, you don't need the readFile function at all, instead all you need is the reading loop:
outputFile.open("saleschart.txt");
if (!outputFile)
{
// Failed to open the output file
return 1;
}
inputFile.open(fileName);
while(inputFile >> storeNumber >> salesData)
{
display(outputFile, salesData, storeNumber);
}
Can someone explain to me why this isn't doing what I want it to do? I want the user to be able to input at least 5 items, however, I want to ensure that all items are unique. When they input the name of the item I want it to subsequently (check that there isn't another item already in there with the same name). I've got a (ranged based for loop) that iterates through the vector, however, when I put in two the same it doesn't loop back to the start it just continues, and for some reason it only checks and iterates through the vector once. Can someone please help me out? I've been working for hours trying to solve this.
bool Items::CheckIfItemExists(std::string &sInputName)
{
for(const auto &Item : ItemsVec)
{
if (Item.GetItemName() == sInputName)
{
std::cout << "Item failed to add as there is already an item called that.\n";
std::cin.clear();
return false;
}
}
return true;
}
void Items::AddNewItem()
{
bool bValid = false;
std::string sInputName;
double dInputSalePrice = 0;
int iInputQuantity = 0;
do{
std::cout << "Enter information for new item...\n";
std::cout << "\tName: ";
std::cin.ignore();
std::cin.clear();
std::getline(std::cin,sInputName);
bValid = CheckIfItemExists(sInputName);
}while(bValid == false);
bool bSalePriceValid = false;
do{
std::cout << "\tSale price: £";
std::cin >> dInputSalePrice;
if(!std::cin)
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
std::cout << "\n";
std::cout << "Sorry, invalid input input. Try again!\n";
std::cout << "\n";
}
else
{
bSalePriceValid = true;
}
}while(bSalePriceValid == false);
bool bQuantityValid = false;
do{
std::cout << "\tQuantity sold: ";
std::cin >> iInputQuantity;
if(!std::cin)
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
std::cout << "\n";
std::cout << "Sorry, invalid input input. Try again!\n";
std::cout << "\n";
}
else
{
bQuantityValid = true;
}
}while(bQuantityValid == false);
Item NewItem(sInputName, dInputSalePrice, iInputQuantity);
ItemsVec.push_back(NewItem);
std::cout << "You've succesfully added a new item.\n";
}
I believe the issue comes from the first call to std::cin.ignore();
When you first get an item name it ignores the first letter (so if you entered 'apple' you'd get back 'pple'). When you loop back to adding an item (I think) that same ignore call removes a newline so when you enter a name again you get the full name (e.g. 'apple').
I think things may work if you move the first call to std::cin.ignore(); to after wherever you call AddNewItem() in a loop.
I put a do/while loop in my password function but it doesn't work. I use xcode10 to code c++ and when I use a semicolon after the while statement it shows an error saying code will never execute
string password (string g)
{
string ch = "hello" ;
cout << "Enter password";
getline(cin, g);
do {
if (ch.compare(g) != 0) {
cout << " INCORRECT PASSWORD";
return (0);
} else {
cout << "correct password";
return (string(g));
}
} while (ch.compare(g) == 0); //this is where it shows the error that the code will never exec
}
I wanted to put this loop and a few other things so I can make this a infinite loop till you enter the correct password.
Well in your if statement you will return in both cases causing the function to stop so it will never get to the while condition to test it
string password(string g)
{
string ch = "hello";
cout << "Enter password\n";
do
{
getline(cin, g);
if (ch.compare(g) != 0)
{
cout << " INCORRECT PASSWORD\n";
}
else {
cout << "correct password";
return (string(g));
}
} while (ch.compare(g) != 0);
}
You need to check if you get input at all too, in case of EOF.
string password() { // you don't need g as parameters in, your overwriting it
string const ch = "hello"; // make ch const to show it not supposed to change
cout << "Enter password";
string g; // defining g here since now you need it
while (getline(cin, g)) { // check that the read from cin is OK
if (ch != g) { // simple notation for comparing two strings. There's also == available
cout << "INCORRECT PASSWORD. Please try again\n"; // no return if you want to try again
} else {
cout << "correct password";
return g; // you could also return ch here since they have the same content
}
}
cout << "Unable to read line. aborting\n"; // not really a lot you can do if there is no input to read.
return string(); // returning empty string.
}
There is Return statement in the "if" and also in the "else".
You can see that no matter what will be the result of ch.compare(g), the function will return to it's caller.
That's why it will never do the "while".
Try to set the Return statements in different place in the code :)
First of all, thanks to everyone who helps me, it is much appreciated!
I am trying to store a string with spaces and special characters intact into MessageToAdd.
I am using getline (cin,MessageToAdd); and I have also tried cin >> MessageToAdd;.
I am so stumped! When I enter the sample input
Test
Everything works as intended. However if I were to use
Test Test Test
The whole console would just blink fast until I pressed CtrlC.
My style of putting variables at the top I've been told is obsolete. Please forgive me as I am still teaching myself and it's simply force of habit. I will be changing my style shortly after I get this solved :)
void AddMessage() {
ifstream myReadFile;
string str;
string MessageToAdd;
string myMessages[10];
int i; // of course my famous i
static string rowHtmlCloseTags;
static string rowHtmlOpenTags;
string replacement;
myReadFile.open("C:\\Users\\Andrews\\Documents\\Visual Studio 2010\\Projects\\computerclass\\Debug\\outages.htm",ios::in);
i = 0; //the start of my array
rowHtmlCloseTags = "</b></td>"; // value that I want to replace with nothing
rowHtmlOpenTags = "<td><b>";
if(!myReadFile) // is there any error?
{
cout << "Error opening the file! Aborting…\n";
exit(1);
}
if (myReadFile.is_open())
{
cout << endl;
while (!myReadFile.eof())
{
getline(myReadFile, str);
if (str == "<tr>")
{
getline(myReadFile, str); //get the next line cause thats where the <td><b>Outage Message</b></td> is.
size_t foundIndex = str.find(rowHtmlCloseTags); //does the sought string exist in this this line?
if (foundIndex != str.npos) //if not no position
str.replace(foundIndex, rowHtmlCloseTags.size(), replacement); //replace the string
else
std::cout << "Oops.. didn't find " << rowHtmlCloseTags << std::endl; //else throw a bitch
foundIndex = str.find(rowHtmlOpenTags); //does the sought string exist in this this line?
if (foundIndex != str.npos) //if not no position
str.replace(foundIndex, rowHtmlOpenTags.size(), replacement); //replace the string
else
std::cout << "Oops.. didn't find " << rowHtmlOpenTags << std::endl; //else throw a bitch
myMessages[i]=str;
i++;
}
}
}
system("cls");
i=0;
while (i < 10)
{
cout << i << ") " << myMessages[i] << endl;
i++;
if (myMessages[i]=="")
{
break;
}
}
myReadFile.close();
cout << endl;
cout << endl;
cout << "Enter the message you would like to see on the reader board.\n";
cout << "Or enter 911 to go back to the main menu: ";
cin.ignore(1080);
getline (cin,MessageToAdd);
if (str == "911") //go back to the main menu
{
system("cls");
mainMenu();
}
else //insert the message into a blank spot in the array
{
i=0;
while (i < 10)
{
if (myMessages[i].empty())
{
myMessages[i]=MessageToAdd;
break;
}
else
{
i++;
}
}
}
//now rebuild the htm file with the new array
CreateHtmlFile(myMessages);
}
I'll tell you one thing that's immediately wrong with your code, not your specific problem but a hairy one nonetheless.
I'm presuming that your mainMenu() function is calling this one. In that case, you appear to be under the misapprehension that:
if (str == "911") //go back to the main menu
{
system("cls");
mainMenu();
}
will return to your menu. It will not do that. What it will do is to call your main menu code afresh and eventually you will run out of stack space.
I suspect that what you should be doing is having a loop in mainMenu() and that code above should just use return; rather than calling mainMenu() recursively.
That and the fact that I think you should be comparing MessageToAdd against "911" rather than str.
Another thing I would do would be to put some temporary debug code in:
cout << "DEBUG A\n";
i=0;
while (i < 10)
{
cout << "DEBUG B " << i << "\n";
if (myMessages[i].empty())
{
cout << "DEBUG C\n";
myMessages[i]=MessageToAdd;
break;
}
else
{
i++;
cout << "DEBUG D " << i << "\n";
}
cout << "DEBUG E\n";
}
cout << "DEBUG F\n";
and see what gets printed. Of course, you could trace the execution in a debugger but that would require you to do the work yourself. If you just post the output (first 100 lines if it's huge), then we can probably tell you what's wrong easily.
Actually, I think your problem is the cin.ignore. When I run your code, nothing works, neither Test nor Test Test Test. That's because it's ignoring the first 1080 characters I'm trying to input. Proof can be seen when you change those statements to:
cin.ignore(1);
getline (cin,MessageToAdd);
cout << MessageToAdd << "\n";
and you get est output when you enter test.
Take out the ignore line and try again. I'm not certain of this since you seem to indicate that Test works but I can't see this as being correct.
So here's what you need to do (at a bare minimum):
get rid of the cin.ignore altogether.
use return rather than mainMenu().
use if (MessageToAdd == "911") instead of if (str == "911").
let us know how it goes then.