string operations and odd results - c++

first post so my apologies if I break protocol.
I'm working on a silly program for school and I have the following code.
cout << "//Dictionary Program//\n\n";
cout << "Enter a command:\n's' - to search for a pattern at the beginning\n";
cout << "'e' - to search for a pattern at the end\n";
cout << "'c' - to search for a pattern anywhere in the word\n";
//Gather user input.
cout << "Please enter a command ('q' to quit): ";
cin >> userCommand;
cmdCheck = userCommand.find("secq");
while(cmdCheck < 0 || userCommand.length() > 1){
cout << "Please enter a valid command\n";
cin >> userCommand;
cmdCheck = userCommand.find("secq");
}
This is driving a menu and I am trying to validate the input. It should be one letter, and one of the following "secq"
I am having a terrible time with the string.find() in the immediate window. I end up with CXX0047: Error: argument list does not match a function. Which I don't understand at all because I am using it elsewhere.
The while condition is not being nice to me. When I give the program a "v" it ends up inside the block like it should, but then I give it an "s" where the cmdCheck should evaluate to 0, but it gives a -1 and stays inside the block.
Lastly, I coded around another error with the cmdCheck but I had that in the while condition and it was not working either. while(userCommand.find("secq") < 0 ...
My inital thought was a problem with the input buffer but when I look at the userCmd variable in the Locals window I have a character array of size 1. There is only the letter and no junk from the buffer (as far as I can tell)
I know I could just tie a bunch of || together with each command but this is a bit more elegant in my opinion. I looked at my final last year and my conditionals were ugly. It's more of a matter of principle at this point.

The expression userCommand.find("secq") tries to find the string "secq" in userCommand. From the sounds of it, you actually want to do the exact opposite, i.e., find the userCommand in the string "secq":
std::string::size_type cmdCheck = std::string("secq").find(userCommand);
while (cmdCheck == std::string::npos) {
...
}
Also note that std::string doesn't return an int. Instead it returns a std::string::size_type. This may be a typedef for int but it may also be a typedef for a different integer type. If the string being passed to find() can't be found, std::string::npos is returned. The exact value for this constant is also not defined so you are best off comparing to this constant instead of making any assumptions.

I'm guessing that userCommand is an std::string. Since the command is supposed to be a single character, use a char instead of a string. Then just use the value as the argument in a switch statement, with appropriate cases for the valid characters and a default case that gives an error message.

Take input using getline in a string.
getline (cin, userCommand) ;
If the input is one letter, take it in a single char. If you insist on taking it in a string, use its first index to check.

Maybe a loop like this would be more appropriate:
char result;
std::cout << "Your command: ";
for (std::string line; ; )
{
if (!(std::getline(std::cin, line))
{
std::cerr << "Fatal error: Unexpected end of input!\n";
std::exit(1);
}
if (line.size() == 1 && line.find_first_of("secq") == 0)
{
result = line[0];
break;
}
std::cout << "Sorry, I did not understand. Please say again: ";
}
std::cout << "Thank you! You said, '" << result << "'\n";
Now if the loop breaks, result will contain the user input.

Related

console not returning expected number of characters in cin buffer

I am creating a console version of "Bull Cow Game". In the game, the user has a certain number of tries to guess what the secret word is. Every time they guess, the program returns the number of "Bulls" and "Cows" they guessed correctly. The user gets a "Bull" for every character that they guess in the right place and a "Cow" for every character that they guess correctly but is not in the right place.
My problem is in my getGuess() function. In the do-while loop, the program is supposed to loop if the user inputs anything other than the number of characters in "answer". When I run my program, I get some unexpected and confusing results:
1) No matter what I input for the first "guess", the program tells me that cin's gcount() is 0 or 1 characters after setw(). I could input 50 characters or 2 and the program would output the same result. If the gcount is 1, then this counts as one of the allotted guesses which is an undesirable result. If the cin.gcount() is 0, the program correctly does not count the guess as valid but I am still confused as to why the cin.gcount() is 0 at all.
2) If I change the number of characters in my guess from the previous guess, the program tells me that the cin.gcount() is whatever the cin.gcount() was after the previous guess instead of after the current guess. This is also an undesirable result since if the user decides to input the correct number of characters, the program will not accept the user's guess as valid.
I am confused as to why this is happening since isn't cin.ignore() supposed to dump all of the extraneous characters that setw() doesn't accept? Why would the number of characters in the cin buffer carry over from one guess to the other?
Here is the function in question:
string getGuess()
{
string guess = "";
const int MAX_LENGTH = 4;
/*ensures that "guess" is the same length as answer. This
will make it so that the program avoids comparing "guess"
to "answer" if "guess" has more characters than "answer".
This do-while loop also ensures that a user can't overflow
the cin buffer by theoretically inputting more characters
than the buffer could contain*/
bool endLoop = false;
do {
cout << "Enter a word containing exactly " << MAX_LENGTH << " characters: ";
cin >> setw(MAX_LENGTH) >> guess;
cout << "cin.gcount() after setw(): " << cin.gcount() << " characters" << endl;
/*ensures that the only character in the cin is '\n'. Otherwise
do-while loop continues*/
if (cin.gcount() != 1)
{
cout << "Invalid number of characters. Please input exactly " << MAX_LENGTH
<< " characters" << endl;
}
else
{
endLoop = true;
}
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "cin.gcount() after cin.ignore(): "
<< cin.gcount() << " characters" << endl;
cout << "guess: " << guess << endl;
cout << endl;
} while ( endLoop == false );
cout << endl;
return guess;
}
Note: This was compiled with Microsoft Visual C++, ISO standard c++17.
A couple of misunderstandings I think
1) gcount only tells you how many characters have been read after an unformatted input operation, cin >> guess is not an unformatted input operation.
2) setw on input does not limit the numbers of characters read. If less than the specified width characters are read then the input is padded to make it equal the given width, but it does not stop more characters being read.
Your code is too tricky, forget about fancy I/O operations, do it the straightforward way. Just read a line of characters into a string using getline and check if the characters entered are what you expect. For instance remove the spaces at the beginning and end of that string, then check for internal spaces and finally check if the string is the length you require.

Check if returned value is integer or char

I have a little "blackjack" program coded in C++. The thing is that the program asks questions like "Would you like... (y/n)?" where user needs to type y/n. I want to check if the value returned is actually the type that I want. So function that should return int, returns int and function that should return char, returns char, before it actually returns something.
I would need some suggestions guys. I think it's not that difficult, I just can't find any solution. Thank you.
Code:
char pickCard(){
char aCard;
std::cout << "Would you like another card?";
std::cin >> aCard;
if (aCard is a char){
return aChar;
} else {
std::cout << "Not a char!";
}
}
I think you have a misconception of exactly how std::istream's formatted input works. In your example, aCard must be a char, because you've declared it as such. If the use enters more than one character, one character will be put into aCard, and std::cin will hold onto the other characters and give them to you the next time you call operator>> (or any other input function); if the user enters a number, aCard will be the character representation of the first digit of that number.
Keep in mind that operator>> knows what type of variable you've given it, and it will ensure that the user's input is valid for that type. If you give it an int, it will make sure the users input is convertible to an int or give you 0 if it isn't. A variable can never be anything but the type you declared it to be.
If you're interested in chars in particular, there's a whole bunch of character classification functions you can use to tell what sort of character (letter, digit, whitespace, etc.) you're working with, but keep in mind that char foo('4') is entirely different than int foo(4).
I guess you just want to know if the input string is in number format. >> will set the istream's failbit if it cannot convert the input string to int.
int num;
if (cin >> num) { // input is "123abc", num == 123
cout << "yes, input is a number. At least start with some figures. "
cout << "num == " << num;
} else { // input is "abc" , error
cout << "no, input is not a number or there is some kind of IO error."
}
If you want to force y or n as only allowed characters you can do:
char pickCard(){
std::string response;
std::cout << "Would you like another card?";
std::cin >> response;
if (response=="y" || response=="n"){
return response[0]; //or anything useful
} else {
std::cout << "Not a char!";
//... more code here
}
//... more code here
}
you can use length() property of std::string to find its length. a string of length one is a char in most cases.

How to break out of this for loop: `for (; cin >> A;);`

for (cout << "\nEnter the Sentence now:";
cin >> Ascii;
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)Ascii + RandomNumberSubtract << endl);
Probably the best advice is don't be clever. Not only do you make it hard for anyone else* to read, understand, and modify your code, you run a real risk of outsmarting yourself.
Thus, don't try to do weird and clever things to implement your loop. Just do things naturally. If they don't naturally fit into how for or while or do ... while statements are structured, then just write a generic loop and use break statements to deal with leaving the loop. e.g.
while (true) {
// Some stuff
if (i_should_break_out_of_the_loop) {
break;
}
// Some more stuff
}
This is pretty much always better than doing things like torturing the for statement in the way you have.
Once you have a clear, easily comprehensible loop, it should be relatively easy to modify it to suit your needs. (or to ask a clearer and more focused question)
*: "anyone else" also includes you three weeks from now, after you've had time for it leave your short term memory.
I strongly advise you to turn this loop into a while loop. However the following is true whether or not you do:
Just enter an EOF, then the loop will terminate.
How an EOF is input will depend on your OS (and possibly also on your terminal settings). On Linux (under default terminal settings) you get an EOF pressing Ctrl+D at the beginning of the line. On Windows, I think it's Ctrl+Z. On Mac I have no idea.
Of course you could also redirect stdin for your program to come from a file (in which case EOF is — as you would guess — generated at the end of file), or from a pipe (in which case EOF is generated as soon as the writing program closes the pipe).
If the variable Ascii is not of type char or string, you may also enter something that cannot be parsed as that variable's data type (e.g. if reading an int, anything other than a number will cause the stream to report failure and thus the loop to terminate).
You also might want to add another end condition then in the loop body (which in your for loop is currently just an empty statement). For example, you might decide that a percent sign should terminate your loop; then you could write (I'm still assuming the type of Ascii which you didn't provide is char):
cout << "\nEnter the Sentence now:";
while(cin >> Ascii)
{
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)Ascii + RandomNumberSubtract << endl);
if (Ascii == '%')
break;
}
However note that normally operator<< skips whitespace; I guess you don't want whitespace skipped. Therefore you probably shouldn't use operator<< but get; this will also allow you to use the end of line as end condition:
cout << "\nEnter the Sentence now:";
while(std::cin.get(Ascii) && Ascii != '\n')
{
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)Ascii + RandomNumberSubtract << endl);
}
However in that case, it's better to read the line in one step and then iterate through it:
cout << "\nEnter the Sentence now:";
std::string line;
std::getline(std::cin, line);
for (std::string::iterator it = line.begin; it != line.end(); ++it)
{
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)*it + RandomNumberSubtract << endl;
}
Note that in C++11, you can simplify this into
cout << "\nEnter the Sentence now:";
std::string line;
std::getline(std::cin, line);
for (auto ch: line)
{
cout << "The ascii value of each letter you entered, added to the offset factor is: "
<< (int)ch + RandomNumberSubtract << endl;
}

Can you explain HOW bool can control loops?

I'm a beginner programmer in C++ (currently), and I've got a conceptual question.
I'm trying to filter a cin input to ensure that it is a one-or-two-digit integer between 01-04, and if it isn't, to produce an error and ask for a new input.
I'm also using map to give the user a list of options that, upon valid selection, routes inputs (integers) through any of several methods to produce a relevant result, but I'll ask a more specific version of this question elsewhere.
I found a snippet of code at http://www.cplusplus.com/forum/beginner/26821/ that is meant to validate an input. I sort of get it, except where the boolean condition is set inside the while loop. Because I don't understand it, it makes it very difficult to edit or make sure that I'm manipulating it right.
Here is the example code:
int main()
{
int num;
bool valid = false;
while (!valid)
{
valid = true; //Assume the cin will be an integer.
cout << "Enter an integer value: " << endl;
cin >> num;
if(cin.fail()) //cin.fail() checks to see if the value in the cin
//stream is the correct type, if not it returns true,
//false otherwise.
{
cin.clear(); //This corrects the stream.
cin.ignore(); //This skips the left over stream data.
cout << "Please enter an Integer only." << endl;
valid = false; //The cin was not an integer so try again.
}
}
cout << "You entered: " << num << endl;
system("PAUSE");
return 0;
And here is my code (the entire thing, to give context). I don't think it's complete, I just want to make sure I'm using the boolean right.
float _tmain(float argc, _TCHAR* argv[])
{
bool validInput = !true;
map<string,int> Operations;
Operations.insert(pair<string, int>("Addition", 01));
Operations.insert(pair<string, int>("Subtraction", 02));
Operations.insert(pair<string, int>("Multiplication", 03));
Operations.insert(pair<string, int>("Division", 04));
cout << "Welcome to OneOpCalc, what operation would you like to perform?" << endl;
for(map<string, int>::iterator ii=Operations.begin(); ii!=Operations.end(); ++ii)
{
cout << (*ii).second << ": " << (*ii).first << endl;
}
while (!validInput)
{
cin >> operatorSelection;
if (cin.fail() || operatorSelection < 4 || operatorSelection > 1)
{
cout << "Error: Invalid selection. Please choose a valid number." << endl << endl;
cin.clear();
cin.ignore();
}
}
}
Does while (!valid) mean "While valid is false"? In my head, it's saying "While valid is !valid", which obviously, would always be false.
EDIT: Thanks for the answers guys, I'm looking through them all. One answer I keep getting goes too general; I understand that ! is NOT, and I understand the concept of flipping the bool using it. However the implicit logical implications are what confuse me. In any given statement, I am used to thinking of !valid as a way of flipping the valid value; Not testing a condition. It's the syntax of using it to test a condition that tricks me. In other words, writing while(!valid) reads literally to me as while(NOTvalid), not while(valid==false). I can't get myself to understand why in this case, !valid reads as a condition and not just a bit-flip.
Loops (and ifs) are controled by an expression of type bool.
In while ( !valid ), the expression is !valid, the operator
not applied to the value of the variable valid.
while ( !valid ) means (literally) while the expression
!valid (which means "not valid") is true.
For the rest, the code you're copying is pretty bad. I wouldn't
use it as an example if I were you.
As for your own code:
_tmain is very particular to Microsoft. You don't want to
use it. If your writing a console application, just use main.
(Same thing holds for _TCHAR, rather than char.)
Neither _tmain nor main can return a float. The return
type of main should always be int. I'm less familiar with
_tmain, but it's either int or void. (Probably int, if
you're in a console mode program.)
!true is false. Always. (Programming is different than
the real world. There are no maybes.) Why be more
complicated than necessary?
There's no need for the flag variable at all. You
can just write:
cin >> operatorSelection;
while ( !cin || operatorSelection > 4 || operatorSelection < 1 ) {
// ...
}
In case of error, you currently only ignore a single
character. You probably want to ignore up to and including the
end of line.
(std::cin.ignore( std::numeric_limits<std::streamsize>::max() );.
And the condition in your if will always be true. (See my
version above.) Where do you expect to find a number which is
neither less than for nor greater than one?
In your code, inside the loop, just add:
else
validInput = true;
after the if closing bracket.
You want to get out of it once the user has typed a correct value.
You want to run the loop "while there is not a valid input". Remove the non-bold words, and translate to C++.
Of course, the second case is not working, because nothing changes validInput inside the loop, so it stays "invalid", and the loop continues forever (And if you want to set something to false then bool validInput = !true; is more convoluted than bool validInput = false; - the compiler will do the same thing, but someone reading the code will have to think to see what it does - it is a good thing to think when reading code, but it's not a good thing to write code that is more complicated than necessary...).
A while loop has a condition and a body, the body is executed as long as the condition evaluates to true.
From the C++ standard:
6.5.1 The while statement
In the while statement the substatement is executed repeatedly until the value of the condition (6.4) becomes
false. The test takes place before each execution of the substatement.
A while loop can have one of the following forms
while ( condition ) statement
while ( condition )
{
statement(s)
}
The ! operator is a logical not and this is how you should read it: while not valid. You could have also written that as:
while(valid == false)
or
while(valid != true)
Note that here, again, != is equivalent to not equal.
nijansen forgot to add the most elegant one
while(!valid)
which is the same as the 2 others

string program for ice cream shop (Edited again) [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
With the assistance of others, I have redone the code from scratch due to them pointing out numerous errors and things that wouldn't work. Thus I have changed the code massively.
I have the program working other than two formatting settings that I can't figure out how to get to work.
I need to only print "DAILY SCOOP REPORT" once at the top of the output, but I've moved it around but due to the way the arrays are set up I don't know where to put it.
Here is my code:
#include <iostream>
include
include
include
include
include
using namespace std;
int main()
{
string flavor_input, Capitalize;
string flavors[] = { "Chocolate", "Vanilla", "Strawberry", "Mint", "Rocky Road", "Mocha" };
int scoop_count [6] = { 0, 0, 0, 0, 0, 0 }, scoops = 0, j, k;
bool valid_option;
cout << "Welcome to Frozen Tongue Ice Cream Shop\n"<<endl;
cout << "Flavors avaliable: "<<endl;
cout << "Chocolate "<<endl;
cout << "Valnilla "<<endl;
cout << "Strawberry "<<endl;
cout << "Mint "<<endl;
cout << "Rocky Road "<<endl;
cout << "Mocha \n"<<endl;
while(true) {
cout << "Please enter the flavor of icecream sold or 'STOP' to exit.\n"<<endl;
getline (cin, flavor_input); // getline causes rocky road to be accepted with a space between the words.
string::iterator it( flavor_input.begin()); //converting the first letter of input to uppercase if not already.
if (it != flavor_input.end())
flavor_input[0] = toupper((unsigned char)flavor_input[0]);
while(++it != flavor_input.end())
{
*it = tolower((unsigned char)*it);
}
if (flavor_input == "STOP" || flavor_input == "Stop")
break;
valid_option = false;
for(int i=0;i<6;i++) //Checks to see if input matches those of possible inputs.
if(!flavor_input.compare(flavors[i]))
{
valid_option = true;
break;
}
if(!valid_option)
{
cout << "Invalid Flavor. Try again.\n\n";
flavor_input.clear();
continue;
}
for(int i=0;i<6;i++)
{
if(!flavor_input.compare(flavors[i]))
{
cout << "Enter how many scoops were sold: ";
cin >> scoops;
cin.ignore();
scoop_count[i] += scoops;
scoops = 0;
cout << '\n';
break;
}
}
}
for(int i=0;i<6;i++)
{
if(!scoop_count[i])
continue;
else
{
cout << "\nDAILY SCOOP REPORT: "<<endl;
cout << setiosflags( ios::left )
<< setw( 11 ) << flavors[i]
<< resetiosflags( ios::left )
<< setw( 4 ) << scoop_count[i] << endl;
}
}
cin.get();
return 0;
}
Thanks again for all of the assistance. It is greatly appreciated.
Thanks to all the assistance and pointing me in the direction of what to study, I have the program completed other than one last part.
I figured out that why it wasn't working when I moved the "DAILY SCOOP REPORT" line around. I had renamed the file and when I compiled it, it was outputing the "last working configuration" kinda deal if that makes sense. So I created a new project (the .cpp file has to have a certain name for submission) and put the code in it. Now the line is printed only once.
In the code block below, I have it where it lowers casing for all other letters other than the first or so it seems to be doing. The reason I have the case coding the way I do is that the instructions want the flavor report to print out with first letter of each word cap and lower after that. I am going to look into how to cap the 2nd "R" in Rocky Road, but other than the ignore white-space I don't really know how. Do I need to parse the line?
Anyone to point me in the right direction would be appreciated.
I tried but it gives error that in the first if statement "syntax error : identifier 'flavor_input'".
//converting the first letter of input to uppercase if not already.
string::iterator it( flavor_input.begin());
if flavor_input = "rocky road"
(it != flavor_input.end())
flavor_input[6] = toupper((unsigned char)flavor_input[6]);
if (it != flavor_input.end())
flavor_input[0] = toupper((unsigned char)flavor_input[0]);
while(++it != flavor_input.end())
{
*it = tolower((unsigned char)*it);
}
switch doesn't work with strings.
You need to use the operator == to select the right choice like so:
string count = // ... something
if (count == "choc") {
}
else if (count == "van") {
}
else if (count == "str") {
} // .. etc
A few other things: make sure you spell string with a consistent case, all lower case and no upper case. String is something different than string.
Make sure you surround strings with double quotes "" and not single quotes ''. single quotes are for single characters like 'a' or 'b'. double quotes are for multiple characters strings like "abc" and "hello"
Having the word count as both the function name and an argument name is probably a bad idea and will not compile because the same name means two different things.
You can't return multiple values from a function. writing something like return a,b,c; doesn't mean what you probably want it to mean. the comma (,) operator allows several expressions to be evaluated in the same statement and the result is the value of the last expression so writing return 1,2,3; is exactly the same as writing return 3;
C++ cannot switch on a string. Replace your switch(count) {...} with if/else if statements. Additionally the proper format for a string is "string", not 'string' (single quotes designate a single character, like: 'a'). Also, ensure that you always use the correct casing for string objects (string as opposed to String, like you have as your return values)
Other than that, it would be helpful to see the compiler errors you are getting.
Another thing I noticed in your source: you will have to omit the semicolons (-cola?) at the end of the following lines:
cout << "Please enter the flavor of icecream sold or 'STOP' to exit.\n"<<endl
<< "Flavors avaliable:\n"<<endl
<< "chocolate\n"<<endl
<< "valnilla\n"<<endl
<< "strawberry\n"<<endl
<< "mint\n"<<endl
<< "rocky road\n"<<endl
<< "mocha\n"<<endl
<< "Enter flavor : ";
This is just a single huge expression. The same applies to
cout << "\nDAILY SCOOP REPORT: \n"<<endl
<< "chocolate :"<<chocolate<<"\n"<<endl
<< "vanilla :"<<vanilla<<"\n"<<endl
<< "strawberry :"<<strawberry<<"\n"<<endl
<< "mint :"<<mint<<"\n"<<endl
<< "rocky road :"<<rocky_road<<"\n"<<endl
<< "mocha :"<<mocha<<"\n"<<endl;
Also: the endl and the "\n" are redundant. You will see the choices being separated by empty lines.
I haven't looked at the whole thing, but this isn't going to do what you want:
if (flavor = 'STOP' || 'stop')
I think you need:
if (flavor.compare("STOP") == 0 || flavor.compare("stop") == 0)
Let's go down the problems I see.
String count (string& flavor, string& count, string& chocolate, string& vanilla, string& strawberry, string& mint, string& rocky_road, string& mocha);
You're using String here, I'm sure you meant std::string or just string.
Inside the count function (SO is truncating the code when pasted), you're ending the line with a semicolon after endl yet trying to continue the stream output. I think you meant
Next:
if (flavor = 'STOP' || 'stop')
I think you meant to use the operator== instead of operator=, which is assignment not comparison. Also, there are no junctions in c++, so you will have to write that out as:
if (flavor == 'STOP' || flavor == 'stop')
Next:
switch (count) { case 'choc' :
Two problems here. First, you can only use plain-old-data (pod) in switch statements. Using std::string in a switch will not automatically call operator==; you will have to use if/else statements. Also, string literals are double quoted whereas character literals are single quoted.
Next:
chocCount + count;
This isn't really a statement. I'm sure you meant chocCount += count;
Next:
if (flavor = chocolate) chocCount + count;
Again, you want to use == and chocCount += count;.
Most of these problems are repeated. You should fix each of these problems everywhere they exist. There may be other problems, but I was basically compiling that in my head.
I didn't read through all of it to find semantic problems, but your count function is clearly not returning a count (at least what I currently see posted). You are returning a String, which I assume you meant string.
That's all this human compiler is going to solve for 1 homework assignment. I could recommend you go read a good C++ tutorial.