Currently, I'm trying to input a users choice into a text file. I have done this part, but for my while loop, I have an exit option as a string. It also prints "exit" into the file and I can't figure out a way to stop it from doing this. getName simply gets the users input and getNum does the same but with numbers. I've tried finding a solution to this, but every attempt I've made hasn't been succesful. I'd really appreciate any feedback, as I'm quite new to coding.
while (m.menu == "1")
{
m.getName();
writeFile << m.name;
if (m.name == "exit")
{
break;
}
m.getNum();
writeFile << m.number;
if (m.number == "exit")
{
break;
}
}
Related
Bit of a long post, but I'm having difficulty trying to make this program read through the entirety of a text file instead of what it seems like just the first line.
// return true only if the code is valid
bool PriceList::isValid(string code) const {
ifstream myfile;
string line;
myfile.open("pricelist.txt");
if (myfile.is_open()) {
while (getline(myfile,line))
{
if (line.find(code) != string::npos)
{
cout << line <<endl;
return true;
}
else
{
cout << line <<endl;
return false;
}
}
}
else
throw invalid_argument("Could not open file");
}
The goal of this part of this program is to determine whether a product bar-code in a text file exists or not. Here is part of the text file (pricelist.txt) that was given to us (categories from left to right are name, barcode, price and taxable):
Soda_can 1035851680 2.29 1
Red_Cabbage 1163115674 1.99 0
Tomato_Sauce 1195034963 0.29 0
Tuna_chunky_in_water 1304271912 0.59 0
Salad_Dressing 1352230364 1.39 0
Here is the code snippet of the main class that tests this function. The addEntry lines calls the addEntry function I already coded to add each item to the end of the text file (we are mainly focusing on the bar-code data values i.e. 1000, 2000). The testAnswer lines calls a function to state whether or not the function is running properly. The first data value is the title of the test, the second is the variable to be tested and the third is the value the function should result in. So for example the first testAnswer line is testing whether or not the barcode 1000 is in the text file and the result is suppose to be true:
{ PriceList priceList;
priceList.addEntry("Apples", "1000", 1.99, false);
priceList.addEntry("Bananas", "2000", 0.99, false);
testAnswer("PriceList isValid1", priceList.isValid("1000"), true);
testAnswer("PriceList isValid2", priceList.isValid("19"), false); }
So as I've said I am having trouble making the program read all of the text file. It only seems to be reading the first line, the Soda_can one and it causes both testAnswer functions to result in false. Here is the current output:
Soda_can 1035851680 2.29 1
FAILED PriceList isValid1: expected 1 but received 0
Soda_can 1035851680 2.29 1
PASSED PriceList isValid2: expected and received 0
If I manually put the Apples and Bananas data values at the very top it results in correct values but obviously I want to make it work for any item anywhere on the text file. I've spent hours trying to solve this and this is the best I've got right now. I'd greatly appreciate any help in this and I thank you for reading all of this if you have. Let me know if any of my explanations are unclear.
Inside your while clause you are calling return in both the if and else sections. This will end processing completely for the function. There is no way for the while clause to reach the second iteration.
The actual problem is that your program returns irrespective of result of code checking if (line.find(code) != string::npos).
Probably, you would like to continue search/reading through file if code is not found and stop reading file once code is found. This should continue till EOF is reached.
You can use an additional variable like bFound to store result and return it. Like in code below:
bool bFound = false;
while (getline(myfile,line))
{
if (line.find(code) != string::npos)
{
cout << line <<endl;
bFound = true;
break; //Record found break from loop
}
else
{
cout << line <<endl;
continue; //Record not found. Continue loop.
}
}
return bFound;
void Manager::ManagerView1()
{
system("cls");
string Ipass;
string Opass;
ifstream Password("Password.txt", ios::in);
if (!Password)
{
cerr << "Check File Integrity";
}
else
{
while (!Password.eof())
{
getline(Password,Ipass);
cout << "Enter Password :\n";
cin >> Opass;
if (Opass == Ipass)
{
cout << "Passwords Match";
}
}
}
}
Text inside the "Password.txt":
Abhik Ray 1123
The password is being read properly, I have already checked that.
When I run the code it lets me enter the password but then the Passwords match doesn't show up as it should. And then it again asks for the password where I am unable to enter it. And then it just quits.
What should I change?
You have several problems, like trying to match only one line from the password file at a time.
The reason for the message is that if (Opass == Ipass) compares the addresses of the character arrays, not their contents.
If you had used std::string to store the strings, the comparison would have worked, but with C style strings you need to use if(strcmp(Opass, Ipass) == 0).
You might also want to check this question for how to terminate the loop:
Why is iostream::eof inside a loop condition considered wrong?
In the new version of the code with cin >> Opass; the >> will only read one word at a time (it stops at each space). So if you type Abhik Ray 1123 you will only get Abhik in Opass, and the rest of the line will remain in the input buffer until the next read.
That's also why it doesn't ask for the next input, it just reads the following words that are already there.
To read a whole line of input, you need to use getline(cin, Opass);, just like when you read from the textfile.
Opass and Ipass are pointers and by doing Opass == Ipass you check if they point to the same area in the memory.
You have to use strcmp to compare their values.
I'm starting with C++ in college (before used Modula2). I have problems with cin.
While interacting with the user, I need to recognize certain "commands".,
For example "addClient Rafael". I handle it the following way
cin >> command, strcoll (command, "addClient"), and then, if command equals addClient, y do
cin >> command2 (so I read Rafael),. and do the proper procedures...
But also, I have to recognize "deleteAll" which deletes all my database, so I dont have to read the second parameter.
When someone enters random things such as "skjdsjfnsdj" its supossed to say "Wrong command" for which, if command didnt equal none of my "known" commands it printf "wrong command".
The problem is, when some types "skajskajs jakasjkajs" it says "wrong command. worng command"... it should only say it once...
So, "noskip" i thing is no use, maybe if i could break the string.., maybe a simpler way, help anyone?
The most flexible and intuitive way to do this is as follows:
bool done = false;
while( !done ) {
string commandLine, cmd, value;
getline( cin, commandLine );
istringstream ss(commandLine);
ss >> cmd >> value;
if( cmd == "deleteAll" ) {
// BOOM
}
else if( cmd == "addClient" ) {
// Do something with 'value'. You could wait until here to read it
// if you want, instead of always attempting to read it.
}
else if( cmd == "quit" ) {
done = true;
}
else {
cout << "Wrong command\n";
}
}
Or edit to suit your purposes. I use this sort of approach for parsing simple key/value pair config files. Works a treat, and takes almost no effort to code.
You could simply try istream::getline() instead.
It will prevent the message appearing more than once for each command (separated by a \n).
Suppose we have a menu which presents the user with some options:
Welcome:
1) Do something
2) Do something else
3) Do something cool
4) Quit
The user can press 1 - 4 and then the enter key. The program performs this operation and then presents the menu back to the user. An invalid option should just display the menu again.
I have the following main() method:
int main()
{
while (true)
switch (menu())
{
case 1:
doSomething();
break;
case 2:
doSomethingElse();
break;
case 3:
doSomethingCool();
break;
case 4:
return 0;
default:
continue;
}
}
and the follwing menu():
int menu()
{
cout << "Welcome:" << endl
<< "1: Do something" << endl
<< "2: Do something else" << endl
<< "3: Do something cool" << endl
<< "4: Quit" << endl;
int result = 0;
scanf("%d", &result);
return result;
}
Entering numerical types works great. Entering 1 - 4 causes the program to perform the desired action, and afterwards the menu is displayed again. Entering a number outside this range such as -1 or 12 will display the menu again as expected.
However, entering something like 'q' will simply cause the menu to display over and over again infinitely, without even stopping to get the user input.
I don't understand how this could possibly be happening. Clearly, menu() is being called as the menu is displayed over and over again, however scanf() is part of menu(), so I don't understand how the program gets into this error state where the user is not prompted for their input.
I originally had cin >> result which did exactly the same thing.
Edit: There appears to be a related question, however the original source code has disappeared from pastebin and one of the answers links to an article which apparently once explained why this is happening, but is now a dead link. Maybe someone can reply with why this is happening rather than linking? :)
Edit: Using this example, here is how I solved the problem:
int getNumericalInput()
{
string input = "";
int result;
while (true)
{
getline(cin, input);
stringstream sStr(input);
if (sStr >> result)
return result;
cout << "Invalid Input. Try again: ";
}
}
and I simply replaced
int result = 0;
scanf("%d", &result);
with
int result = getNumericalInput();
When you try to convert the non-numeric input to a number, it fails and (the important part) leaves that data in the input buffer, so the next time you try to read an int, it's still there waiting, and fails again -- and again, and again, forever.
There are two basic ways to avoid this. The one I prefer is to read a string of data, then convert from that to a number and take the appropriate action. Typically you'll use std::getline to read all the data up to the new-line, and then attempt to convert it. Since it will read whatever data is waiting, you'll never get junk "stuck" in the input.
The alternative is (especially if a conversion fails) to use std::ignore to read data from the input up to (typically) the next new-line.
1) Say this to yourself 1000 times, or until you fall asleep:
I will never ever ever use I/O functions without checking the return value.
2) Repeat the above 50 times.
3) Re-read your code: Are you checking the result of scanf? What happens when scanf cannot convert the input into the desired format? How would you go about learning such information if you didn't know it? (Four letters come to mind.)
I would also question why you'd use scanf rather than the more appropriate iostreams operation, but that would suffer from exactly the same problem.
You need to verify if the read succeeded. Hint: it did not. Always test after reading that you successfully read the input:
if (std::cin >> result) { ... }
if (scanf("%d", result) == 1) { ... }
In C++ the failed state is sticky and stays around until it gets clear()ed. As long as the stream is in failed state it won't do anything useful. In either case, you want to ignore() the bad character or fgetc() it. Note, that failure may be due to having reached the end of the stream in which case eof() is set or EOF is returned for iostream or stdio, respectively.
I want to have a menu display that accepts user input. However, I want the user to be able to go back to the beginning of the menu to reselect options.
while(end != 1) {
display menu options
prompt user for input
if(input == x) {
do this
}
else
do that
}
then, i want it to skip back up to the beginning of the loop and ask the question over again. Howcan I do this without creating an infinite loop of the menu printing across the screen?
Unfortunately you didn't really show the code you are using but rather some pseudo code. Thus, it is hard to tell what you are actually trying to do. From the description of your problem and your pseudo code I suspect, however, that the root of the problem is that you don't check your inputs and don't restore the stream to a reasonably good state! To read the menu selection you probably want to use code akin to this:
int choice(0);
if (std::cin >> choice) {
deal with the choice of the menu here
}
else if (std::cin.eof()) {
// we failed because there is no further input: bail out!
return;
}
else {
std::string line;
std::cin.clear();
if (std::getline(std::cin, line)) {
std::cout << "the line '" << line << "' couldn't be procssed (ignored)\n";
}
else {
throw std::runtime_error("this place should never be reached! giving up");
}
}
This is just a rough layout of how the input would basically look like. It would probably be encapsulated into a function (in which case you'd want to bail out of from a closed input somewhat differently, possibly using an exception or a special return value). The main part of his is to
restore the stream back to good state using std::isteam::clear()
skip over the bad input, in this case using std::getline() with a std::string; you could also just std::istream::ignore() the remainder of the line
There may be other problems with your menu but without seeing concrete code I'd think it is hard to tell what the concrete problems are.
Instead of using a while, consider using a function, so you can call it where you need it:
void f()
{
if(end != 1) {
display menu options
prompt user for input
if(input == x) {
do this
f();
}
else{
do that
f();
}
}
}
I am not sure what your looking for either but this is some rough code of a menu
while(1){
cout<<"******* Menu ********\n";
cout<<"-- Selections Below --\n\n";
cout<<"1) Choice 1\n";
cout<<"2) Choice 2\n";
cout<<"3) Choice 3\n";
cout<<"4) Choice 4\n";
cout<<"5) Exit\n";
cout<<"Enter your choice (1,2,3,4, or 5): ";
cin>>choice;
cin.ignore();
switch(choice){
case 1 :
// Code for whatever you need here
break;
case 2 :
// Code for whatever you need here
break;
case 3 :
// Code for whatever you need here
break;
case 4 :
// Code for whatever you need here
break;
case 5 :
return 0;
}