I have an assignment where I need to create a postfix calculator. I'm running into some difficulties that previous questions regarding the subject on SO didn't cover adequately.
Here's an example of input I want to handle:
12 6 +
2 *
[Carriage return]
Result: 36
The description of the assignment:
The arithmetical expressions we normally use are infix expressions, meaning that the operator appears between its two operands, as in "4 + 5". In postfix expressions, the operator appears after its operands, as in "4 5 +". Here is a slightly more complex postfix expression: "25 12 7 - 2 * /". The equivalent infix expression is: "25 / ((12 - 7) * 2)". The result of that expression should be 2.5 (don't use integer division). Postfix expressions don't require parentheses.
Write a program that uses a stack to evaluate postfix expressions.
Each input expression should be entered on its own line, and the
program should terminate when the user enters a blank line. The only
symbols in an expression will be +, -, *, /, digits and spaces.
Hint: Read a postfix expression from left to right. When you read a
number, push it on the stack. When you read an operand, pop the top
two numbers off the stack, apply the operator to them, and push the
result on top of the stack. At the end, the result of the expression
should be the only number on the stack.
Here's my code so far:
#include <list> /* Linked Lists */
#include <stack> /* Stacks */
#include <iostream> /* cout cin */
int main() {
std::stack< double, std::list<double> > postfixStack;
std::string input;
std::cout << "Enter a postfix expression: ";
std::getline(std::cin, input);
while (input != "") {
std::cout << "Input expression: " << input << std::endl;
for (int i = 0; i<input.length()-1; i++) {
if (input.compare(i, 1, " ")) { // should ignore spaces, but doesn't
std::cout << "Skipping element " << i << " \n";
} else if (static_cast<int>(input[i]) == input[i]) { // push numbers onto the stack
postfixStack.push(static_cast<double>(input[i]));
std::cout << "Pushing " << input[i] << " onto the stack.\n";
} else if (input.compare(i, 1, "+")) { // pop two numbers off the stack (1), apply the operator to them (2), and push that onto the stack (3)
double operand1 = postfixStack.top();
postfixStack.pop();
double operand2 = postfixStack.top();
postfixStack.pop();
postfixStack.push(operand1 + operand2);
std::cout << "Adding " << operand1 << " and " << operand2 << std::endl;
}
}
std::getline(std::cin, input);
}
if (!postfixStack.empty()) {
std::cout << "Result of expression: " << postfixStack.top() << std::endl;
} else {
std::cout << "It appears that you did not enter an expression to evaluate.\n";
}
return 0;
}
Syntax highlighting and line numbers on Gist.
Where I'm struggling:
My while loop should allow more than one line of input per the spec. I was originally using cin instead of getline, but that presented the opposite problem: unlimited lines to enter anything whatsoever, even when checking for /r and the empty string.
I'm trying to skip over spaces in my loop, but instead my conditional appears to skip over anything that isn't a space.
Checking string subscripts means that I can only use numbers with one digit, which definitely isn't what I want. When I encounter a number: I think I could check the next element, if that's a number then I could concatenate them and bump up the loop counter. In theory, at least. I'd like to get basic functionality before I work on that.
My while loop should allow more than one line of input per the spec.
You've already found getline. You can simply use that to read whole lines. That approach you've taken looks fine.
I'm trying to skip over spaces in my loop, but instead my conditional appears to skip over anything that isn't a space.
That's right. You're checking the result of string::compare, but the result isn't a boolean, and non-zero doesn't mean the strings are equal, it means they aren't equal.
The way you've performed the comparison is uncommon, BTW, and more usual would be to simply compare the character to ' ', or to use isspace or maybe isblank.
Checking string subscripts means that I can only use numbers with one digit, which definitely isn't what I want.
Right. When you see a digit, you can enter a nested loop to read all subsequent digits. The base case, a one-digit string, is trivially converted to a number. (But just a tad less trivial than you think, see the note below.) And if you know how to determine the value of an N-digit string (let's say ABC), you can determine the value of an N+1-digit string (let's say ABCD) by multiplying by 10, and adding the value of the next digit.
Note: static_cast<int>(input[i]) == input[i] is always true. This doesn't mean what you think it means. Use your debugger to inspect the value of static_cast<int>(input[i]) for some characters, and try to understand what this cast is doing. When you understand what this does, think about another check you could do instead, and how you can use that, after checking a character is a digit, to determine the numeric value of that digit.
Related
Essentially I am making some recursive calls where it increments and decrements a number that is displayed via cout statements. There are two cout statement iterations(so four of one cout statement, and four of the other) that display this. The first one increments the number from 1 to 4, and the second one decrements the number from 4 to 1. What I want to happen is for each cout statement, depending on the number, I want that many spaces before that specific cout function, except that value minus one. The difference between the first and second cout function is that the second cout function will also print out ALSO(will make sense later when I show my intended output.)
So this is the intended output of the cout functions(the stuff in parentheses is not meant to be taken literally. I was unable to just put spaces behind them because it wouldn't show for some reason. The first and last sentences of the output should have zero spaces behind it.):
This was written by call number 1.
(one space here)This was written by call number 2.
(two spaces here)This was written by call number 3.
(three spaces here)This was written by call number 4.
(three spaces here)This ALSO was written by call number 4.
(two spaces here)This ALSO was written by call number 3.
(one space here)This ALSO was written by call number 2.
This ALSO was written by call number 1.
Here is my code that accomplishes all this EXCEPT the spaces(There should be iostream with the angled brackets surrounding it after include, but it refuses to show for some reason.):
#include <iostream>
using namespace std;
void Waswritten(int numwrite);
int main()
{
Waswritten(4);
return 0;
}
void Waswritten(int numwrite)
{
static int count = 0;
if (!numwrite)
return;
cout << "This was written by call number " << ++count << "." << endl;
Waswritten(numwrite - 1);
cout << "This ALSO was written by call number " << count-- << "." << endl;
}
Call this method from Waswritten
void writeSpaces(int spaceCount){
for(int i=0;i<spaceCount;i++){
cout<<" ";
}
}
before each cout
writeSpaces(count);
so I'm pretty new to C++ and I'm doing an assignment for my class. I ran into a problem when trying to check if an input is a string or a double/int. So I made a basic program to test it
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
string hi;
double hello;
cin >> hello;
if (!cin)
{
//Strings go here
cin.clear();
cin >> hi;
cout << hi << endl;
}
else
{
cout << hello << endl;
}
cout << "Done!" << endl;
}
So it works for basically when inputting a letter (such as "j" or "a") or a number but when inputting "+" or "-" it waits for the next input then forces it through the string block, even if it is a number. However "*" or "/" are read as strings and don't cause that issue (I'm assuming since they aren't explicitly operators)
I assume I am probably missing something. Thank you
Edit: I am testing with single types at a time (such as 123, 1 , d, +) without mixing types, so there won't be any inputs that have a double and a string
As per user4581301's suggestion, I'll put in some examples input and outputs
Inputs:Outputs
"Hello":"Hello"
123:123
"/":"/"
"+" (Input after: 2):"2"
The problem
Your programme does not work exactly as intended, because it doesn't take into consideration potentially consumed but lost characters.
Here are different cases that work as expected:
abc: the first char read is not numeric, so it's not consumed and cin fails fast. The second reading reads every chars present as a string.
123abc456: the first 123 is read. When a is encountered, it is not consumed since it's not valid numeric. Further reading is stopped, but a numeric value could be read.
/123: the first char read is not numeric, so it's not consumed and cin fails. the second reading reads every char present as string.
-123 or +123: the first char is considered as a valid numeric char and is read, and then the remainder is read, still as a numeric value. Works as expected if you consider that a double ora an int can be signed. Depending on output formatting, the + might not appear with your output.
Here are the cases that do not work: if the first char is + or - but it is not followed by a valid numeric char. In this case the first char is consumed, but the next char makes the numeric input fail. The remaining chars are then read as string (except the first sign that was already consumed and is lost). Examples:
++123
+ 123 (the space ends the axtraction of the double that fails, the remainder is read as a string).
Online demo
The solution
The easiest solution is to read the input as a string, then try to convert the string.
For example:
size_t processed;
string hi;
double hello;
cin >> hi;
try {
hello = stod(hi,&processed);
cout<<"number:" <<hello;
if (processed<hi.size())
cout << " (followed by something)";
cout <<endl;
}
catch (...) // should be more precise in catching, but it's for the proof of concept
{
cout <<"string: "<< hi << endl;
}
Online demo
If you want to consider + and - as alphanumeric, it'd be easy to check if hi is non empty and hi[0] a digit before trying to do the conversion.
Alternatively, you could also do a regex check of the string to see if it matches a numeric format.
#include <iostream>
using namespace std;
int main()
{
int loop = 0;
int Pass = 0;
int guess = 0;
cout << "Write In A 4 Digit Number!";
cin >> Pass;
while (loop == 0)
{
guess = guess + 1;
if (Pass == guess)
{
cout << "Your number is" + guess;
}
}
return 0;
}
This mystery code is giving me random outputs. This is a program ment to guess what number you put in. Instead when you input a random number and hit enter it gives you stuff like error and YF and stuff. Try it yourself by testing the code. If you type in 1 and press enter you will get our number is printed out.
our number is
ur number is
r number is
number is
number is
There's some more odd also like if you enter 666 you will get: e::_S_normalize_catory catory not found and if you enter 333 ☻ will print out.
There's plenty more. Some numbers are blank but some are not.
Can someone please tell me why this happends!
CLOSED: THANKS FOR HELPING ME OUT. I CLOSE THIS NOW. YOU CAN STILL CHAT!
You need to change the
cout << "Your number is" + guess;
to
cout << "Your number is " << guess;
In C++, adding a number to a string literal doesn't convert the number to a string; it does something else entirely (pointer arithmetic).
For a backgrounder on pointer arithmetic in C and C++, see Everything you need to know about pointers in C (especially the last section about strings).
The reason your program prints out funny strings is that, once guess gets large enough, the "Your number is" + guess points to some memory after the end of the string literal, and the program prints out whatever happens to be in that memory. (Technically, you're in the realm of undefined behaviour and so your program could legitimately behave in all sorts of strange ways.)
"Your number is" is a char *, and you are adding 'guess' to it. This moves the pointer to somewhere other than the start of the string literal. If the value of guess is small you will end up somewhere inside the string and it will print the subsequent part ok. If you enter a larger number it will access somewhere completely random and cause an error.
Try:
cout << "Your number is: " << guess;
(To use the string + operator at least one part of the input needs to be a string. You have a const char * and an int, so the compiler thinks you want to do pointer arithmetic. Even if you make the string literal into a string you would also need to make guess into a char * using itoa for it to display correctly. Much easier to stick with the stream version using <<.)
By adding an integer value to the address of the string ("Your number is" + guess), you get a new address that points to some character inside the string or to what comes next. Then the cout statement will print all characters from there until the next null byte.
You rediscovered the joys of buffer overflow hacking...
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;
}
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.