I found this code online so I could study stack calculators, but when I try to enter an expression for the program to evaluate, it gives me 78. Every time. I've combed through it to see if I could debug it by myself, but I have no clue how to fix this. I've added the comments myself to make things more readable. Could anyone help?
#include<iostream>
#include<stack>
#include<cmath>
using namespace std;
int pri(char ch) //precedence checking
{
switch (ch)
{
case '-':
case '+': return 1;
case '*':
case '/': return 2;
case '^': return 3;
case '(':
case ')': return 4;
default: return -1;
}
}
int calculate(char op, int l , int r) //actual calculations
{
if(op == '+') return l + r;
if(op == '-') return l - r ;
if(op == '*') return l * r;
if(op == '/')
{
if(r > 0)
{
return l/r;
}
return 0;
}
if(op == '^') return pow(l,r);
return -1;
}
int main(void)
{
string equ;
cout << "Enter an expression: ";
getline(cin, equ);
char math[equ.size()+1];
int l = sizeof(math)/sizeof(char);
stack<char> s;
stack<int> op_s;
int i = 0;
while(math[i] != '\0')
{
if(math[i] == '(')
{
s.push('(');
}
else if(math[i] == ')')
{
while(s.top() != '(')
{
int r = op_s.top();
op_s.pop();
int l = op_s.top();
op_s.pop();
int re = calculate(s.top(),l,r);
op_s.push(re);
s.pop();
}
s.pop();
}
else if(math[i] == '+' || math[i] == '-' || math[i] == '*' || math[i] == '/' || math[i] == '^')
{
int pC = pri(math[i]);
while(!s.empty() && pri(s.top()) >= pC)
{
int r = op_s.top();
op_s.pop();
int l = op_s.top();
op_s.pop();
int re = calculate(s.top(),l,r);
op_s.push(re);
s.pop();
}
s.push(math[i]);
}
else
{
op_s.push(int(math[i])- 48);
}
i++;
}
while(!s.empty())
{
int r = op_s.top();
op_s.pop();
int l = op_s.top();
op_s.pop();
int re = calculate(s.top(),l,r);
op_s.push(re);
s.pop();
}
cout <<"Result: " << op_s.top() << endl;
return 0;
}
OK So I didn't go through everything with a fine toothed combed, but one obvious issue is that the char values from equ are never copied into the math array.
Below I just removed the C style math array and instead loop through the char values in equ (I renamed the equ variable to math).
Also note I only tested this with 5*5, I did not do any further testing beyond that.
/** Removed for brevity**/
int main( )
{
string math{ "5*5" };
//cout << "Enter an expression: ";
//getline(cin, math);
stack<char> s;
stack<int> op_s;
for ( auto i = 0; i < math.size( ); i++ )
{
if( math[ i ] == '(' )
{
s.push( '(' );
}
else if(math[ i ] == ')')
{
while( s.top( ) != '(' )
{
int r = op_s.top();
op_s.pop();
int l = op_s.top();
op_s.pop();
int re = calculate(s.top(),l,r);
op_s.push(re);
s.pop();
}
s.pop();
}
else if(math[i] == '+' || math[i] == '-' || math[i] == '*' || math[i] == '/' || math[i] == '^')
{
int pC = pri(math[i]);
while(!s.empty() && pri(s.top()) >= pC)
{
int r = op_s.top();
op_s.pop();
int l = op_s.top();
op_s.pop();
int re = calculate(s.top(),l,r);
op_s.push(re);
s.pop();
}
s.push(math[i]);
}
else
{
op_s.push(int( math[ i ] ) - 48 );
}
}
while(!s.empty())
{
int r = op_s.top();
op_s.pop();
int l = op_s.top();
op_s.pop();
int re = calculate(s.top(),l,r);
op_s.push(re);
s.pop();
}
cout <<"Result: " << op_s.top() << endl;
return 0;
}
Related
My problem is that my evaluatePostfix() function is not calculating operands. It only returns the top of the stack in the converted postfix expression.
So for example, my output is:
Enter a infix expression: 1+4
your postfix expression is:
14+
your result is:
4
Why am I not getting 5?
Here's my main():
int main()
{
string infixExp = "";
cout << "Enter a infix expression: ";
cin >> infixExp;
cout << "your postfix expression is: " << endl;
infixToPostfix(infixExp);
cout << endl;
cout << "your result is: " << endl;
cout << evaluatePostfix(infixExp) << endl;
}
Here's evaluatePostfix():
int evaluatePostfix(string expression)
{
ArrayStack<int> S;
for (int i = 0; i < expression.length(); i++)
{
if (expression[i] == ' ' || expression[i] == ',') continue;
else if(IsOperator(expression[i]))
{
int operand2 = S.peek();
S.pop();
int operand1 = S.peek();
S.pop();
int result = PerformOperation(expression[i], operand1, operand2);
S.push(result);
}
else if(IsNumericDigit(expression[i]))
{
int operand = 0;
while (i < expression.length() && IsNumericDigit(expression[i]))
{
operand = operand * 10 + expression[i] - '0';
i++;
}
i--;
S.push(operand);
}
}
return S.peek();
}
Here's PerformOperation(), IsOperator(), IsNumericDigit(). These are all in evaluatePostfix.
bool IsNumericDigit(char C)
{
if (C >= '0' && C <= '9')
{
return true;
}
else
{
return false;
}
}
bool IsOperator(char C)
{
if (C == '+' || C == '-' || C == '*' || C == '/')
{
return true;
}
else
{
return false;
}
}
int PerformOperation(char operation, int operand1, int operand2)
{
if (operation == '+')
{
return operand1 + operand2;
}
else if (operation == '-')
{
return operand1 - operand2;
}
else if (operation == '*')
{
return operand1 * operand2;
}
else if (operation == '/')
{
return operand1 / operand2;
}
else
{
cout << "error" << endl;
}
return -1;
}
Lastly, here is infixToPostfix():
void infixToPostfix(string s)
{
ArrayStack<char> stackPtr;
string postfixExp;
for (int i = 0; i < s.length(); i++)
{
char ch = s[i];
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))
{
postfixExp += ch;
}
else if (ch == '(')
{
stackPtr.push('(');
}
else if (ch == ')')
{
while(stackPtr.peek() != '(')
{
postfixExp += stackPtr.peek();
stackPtr.pop();
}
stackPtr.pop();
}
else
{
while (!stackPtr.isEmpty() && prec(s[i]) <= prec(stackPtr.peek()))
{
postfixExp += stackPtr.peek();
stackPtr.pop();
}
stackPtr.push(ch);
}
}
while (!stackPtr.isEmpty())
{
postfixExp += stackPtr.peek();
stackPtr.pop();
}
cout << postfixExp << endl;
}
evaluation of infix expression. there is segmentation fault in line 40.
#include <iostream>
#include <stack>
#include <string>
using namespace std;
int pre(char);
int operation(int, int, char);
int fun(string);
int main() {
string s;
cin >> s;
int res = fun(s);
cout << res;
return 0;
}
// function to get result
int fun(string s) {
stack<int> s1;
stack<char> s2;
for (int i = 0; i < s.length(); i++) {
if (isdigit(s[i])) {
int val = 0;
while (i < s.length() && isdigit(s[i])) {
val = val * 10 + (s[i] - '0');
i++;
}
s1.push(val);
} else if (s[i] == '(')
s2.push(s[i]);
else if (s[i] == ')') {
while (!s2.empty() && s2.top() != '(') {
char oprt = s2.top();
s2.pop();
int v2 = s1.top();
s1.pop();
int v1 = s1.top();
s1.pop();
int r = operation(v1, v2, oprt);
s1.push(r);
}
if (!s2.empty())
s2.pop();
} else if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/') {
while (s2.size() > 0 && pre(s[i]) <= pre(s2.top())) {
char oprt = s2.top();
int v2 = s1.top();
s1.pop();
int v1 = s1.top();
s1.pop();
int r = operation(v1, v2, oprt);
s1.push(r);
}
s2.push(s[i]);
}
}
while (!s2.empty()) {
int v2 = s1.top();
s1.pop();
int v1 = s1.top();
s1.pop();
char oprt = s2.top();
s2.pop();
int r = operation(v1, v2, oprt);
s1.push(r);
}
return s1.top();
}
int operation(int v1, int v2, char oprt) {
int r;
switch (oprt) {
case '+':
r = v1 + v2;
break;
case '-':
r = v1 - v2;
break;
case '/':
r = v1 / v2;
break;
case '*':
r = v1 * v2;
break;
}
return r;
}
int pre(char c) {
if (c == '+' || c == '-')
return 1;
else
return 2;
}
Look at this code:
for (int i = 0; i < s.length(); i++) {
if (isdigit(s[i])) {
int val = 0;
while (i < s.length() && isdigit(s[i])) {
val = val * 10 + (s[i] - '0');
i++;
}
s1.push(val);
}
You use the same variable in both loops. As the result, you would miss some characters. For example: "123()". In this example you would encounter the first digit at the position 0 and start the inner loop. The inner loop would stop at the position 3 where the symbol '(' is located. Then you finish the iteration and the new iteration starts... after the i++ increment of the outer loop. As the result you would miss the symbol.
Sooner or later you would get into this loop, where you check the stack for emptiness one time but pop three times:
while (!s2.empty() && s2.top() != '(') {
char oprt = s2.top();
s2.pop();
int v2 = s1.top();
s1.pop();
int v1 = s1.top();
s1.pop();
int r = operation(v1, v2, oprt);
s1.push(r);
}
Should be no surprise that on some inputs you would get the segmentation fault.
I cant get the char search to work. The substring function is working but the char search won't provide the right location of the char it is looking for
#include<iostream>
#include <string>
using namespace std;
int charsearch(string searchInto, char ch, int start = 0)
{
int x = 0;
long n = searchInto.length();
for (int i = 1; i < n; i++)
{
cout << ch;
if (searchInto[i] == ch)
{
i = x;
}
else
i++;
}
cout<< x;
return x;
}
int substr(string src, string tosearch, int start = 0)
{
string searchInto = src;
long n = searchInto.size();
long m = tosearch.size();
int ans = -1;
for (int i = start; i < n; ++i)
{
int p = i;
int q = 0;
bool escape = false;
while (p < n && q < m) {
if (searchInto[p] == tosearch[q]) {
if (tosearch[q] == '/' && !escape) {
++q;
} else {
++p; ++q;
}
escape = false;
} else if (!escape && tosearch[q] == '*') {
++q;
while (q < m && p < n && searchInto[p] != tosearch[q]) ++p;
escape = false;
} else if (!escape && tosearch[q] == '?') {
++p; ++q;
escape = false;
} else if (tosearch[q] == '/' && !escape) {
escape = true;
++q;
} else break;
}
if (q == m) {
return i;
}
if (q == m - 1 && tosearch[q] == '*') {
if (q > 0 && tosearch[q - 1] == '/') continue;
else return i;
}
}
return ans;
}
int main()
{
string searchInto, tosearch;
cout<< "Enter string:";
getline(cin, searchInto);
cout << "Looking for :";
getline(cin, tosearch);
if (tosearch.length() < 2)
{
char ch = tosearch.at(0);
cout << "Found at: " <<charsearch(searchInto, ch) << endl;
cout << "Used Char" << endl;
}
else
cout << "Found at: " <<substr(searchInto, tosearch) << endl;
return 0;
}
To find a character in a string, you have two interfaces.
std::string::find will return the position of a character you find:
auto pos = yourStr.find('h');
char myChar = yourStr[pos];
If the character does not exist, then std::string::npos will be returned as the std::size_t returned for position.
stl algorithm std::find, in header algorithm returns an iterator:
auto it = std::find(yourStr.begin(), yourStr.end(), 'h');
char myChar = *it;
If the character does not exist, then it == yourStr.end().
There are some silly mistakes in your CharSearch method. First of all, You have to break the loop when you got your target character. And most importantly you are not assigning x when you are finding the target. Furthermore, there is extra increment of value i inside the loop. I have modified the function. Please check it below
int charsearch(string searchInto, char ch, int start = 0) {
int x = -1;
long n = searchInto.length();
for (int i = start; i < n; i++)
{
cout << ch;
if (searchInto[i] == ch)
{
x = i; // previously written as i = x which is wrong
break; // loop should break when you find the target
}
}
cout<< x;
return x;
}
Please note that,you can either also use find method of string or std::find of algorithm to search in string.
You need to make changes as per this code
int charsearch(string searchInto, char ch, int start = 0)
{
int x = -1; // : change, if return -1, means not found
long n = searchInto.length();
for (int i = start; i < n; i++) // : change
{
cout << ch;
if (searchInto[i] == ch)
{
x = i; // : change
break; // : change
}
}
cout<< x;
return x;
}
Note : This function will return 1st match.
I'm a C++ newcomer.
For the next project in class, the professor asked us to code a program that calculates a mathematical expression, that we input an infix notation, convert it to postfix and calculates it. I think I have pretty much finished the code, but there are some lines that I'm probably doing wrong and I don't really know what is it. Can you please take a look at it and tell me why am I wrong.
#include <iostream>;
#include <stack>;
#include <string>;
using namespace std;
bool operatorCheck(char c)
{
if (c == '+' || c == '-' || c == '*' || c == '/')
{
return true;
}
return false;
}
int priority(char c)
{
if (c == '*' || c == '/')
{
return 2;
}
else if (c == '+' || c == '-')
{
return 1;
}
return 0;
}
string InfixToPostfix(string expression)
{
stack<char> operators;
string postfix;
for (int i = 0;i< expression.length();i++)
{
if (expression[i] == ' ')
{
continue;
}
else if (expression[i] >= '0' && expression[i] <= '9')
{
string temp;
temp += expression[i];
int temp2 = i + 1;
while (true)
{
if (expression[temp2] >= '0' && expression[temp2] <= '9')
{
temp += expression[temp2];
temp2 += 1;
}
else
{
break;
}
}
postfix= postfix + temp + " ";
}
else if (operators.empty())
{
operators.push(expression[i]);
}
else if (operatorCheck(expression[i]))
{
if (priority(operators.top()) < priority(expression[i]))
{
operators.push(expression[i]);
}
else
{
while (!operators.empty() && priority(operators.top()) < priority(expression[i]))
{
postfix += operators.top();
operators.pop();
}
operators.push(expression[i]);
}
}
else if (expression[i] == '(')
{
operators.push(expression[i]);
}
else if (expression[i] == ')')
{
while (!operators.empty() && operators.top() != '(')
{
postfix += operators.top();
operators.pop();
}
operators.pop();
}
}
while (!operators.empty())
{
postfix += operators.top();
operators.pop();
}
return postfix;
}
//Main program
int main()
{
string expression;
stack<int> calc;
cout << "Welcome to my program!" << endl;
cout << "This program will help you to calculate arithmetic expression." << endl;
cout << "Please enter an arithmetic expression (Remember to enter space between numbers and operators):" << endl;
getline(cin, expression);
string postfix = InfixToPostfix(expression);
cout << postfix << endl;
for (int i = 0;i < postfix.length();i++)
{
if (postfix[i] == ' ')
{
continue;
}
else if (postfix[i] >= '0' && postfix[i] <= '9')
{
string temp;
int temp2 = i + 1;
temp += postfix[i];
while (true)
{
if (postfix[temp2] >= '0' && postfix[temp2] <= '9')
{
temp += expression[temp2];
temp2 += 1;
}
else
{
break;
}
}
int n = atoi(temp.c_str());
calc.push(n);
}
else if (postfix[i] == '+')
{
int temp1 = calc.top();
calc.pop();
int temp2 = calc.top();
calc.pop();
int result = temp2 + temp1;
calc.push(result);
}
else if (postfix[i] == '-')
{
int temp1 = calc.top();
calc.pop();
int temp2 = calc.top();
calc.pop();
int result = temp2 - temp1;
calc.push(result);
}
else if (postfix[i] == '*')
{
int temp1 = calc.top();
calc.pop();
int temp2 = calc.top();
calc.pop();
int result = temp2 * temp1;
calc.push(result);
}
else if (postfix[i] == '/')
{
int temp1 = calc.top();
calc.pop();
int temp2 = calc.top();
calc.pop();
int result = temp2 / temp1;
calc.push(result);
}
}
cout << calc.top() << endl;
}
For example, with this expression ( ( 7 + 6 ) * ( 16 - 2 ) ) / 2,
It returns 7 6 +16 6 2 -*2 / ( there is an extra 6) for the postfix. Why is this happened?
This program is a part of an exam I just took, that I had to write. I only got this far and couldn't get anywhere. Here is the prompt:"Write a Test Function toDecimal() that converts a roman numeral such as MMLXVII to it's decimal number representation. Use Main() to test the function. The toDecimal() function should have 2 arguments, the string array of roman numerals and a helper function. This helper function will return the numeric value of each of the letters used in roman numbers. Then convert the string arguments as so: Look at the first two characters,if the first is larger, convert the first and add it to the summation, then call the conversion function again with the second value and add both. IF the first character is lesser than the second subtract the first from the second, and add the result to the conversion of the string. without validation it will also convert strings like "IC". VAlidate the string arguement, if there is an error, call the error processing function. Provide at least two error processing functions and test toDecimal() with each. One could be adking the user to correct, the other may correct it."
I,X,C,M cannot be repeated more than 3 times in succession, D,L,V, can never be repeated in succession.I can only be subtracted from V and X,X can only be subtracted from L and C, C can only be subtracted from D and M. V, L, and D can never be subtracted.
I've lost about 2 days worth of sleep on this, tried writing it hundreds of different ways using and breaking the rules. This is the closest I've got on it.
#include <iostream>
#include <string>
#include <map>
#include <algorithm>
#include <cstring>
using namespace std;
bool checker(string roman);
// Adds each value of the roman numeral together
int toDecimal(string, bool* (*function)(string));
int convert(string roman, int i);
int main(){
string roman;
cout << "This program takes a roman numeral the user enters then converts it to decimal notation." << endl;
cout << "Enter a roman numeral: ";
cin >> roman;
transform(roman.begin(), roman.end(), roman.begin(), toupper);
cout << roman << " is equal to " << toDecimal(roman, *checker(roman)) << endl;
}
bool checker(string roman){
int length = roman.length();
for (int count = 0; count < length; count++){
string sub = roman.substr(count, count);
if(sub != "I" || sub != "V" || sub != "X" || sub != "L" || sub != "C" || sub != "D" || sub != "M"){
cout << "Error. Try Again"<< endl;
return false;
}
else if(convert(roman, count) == convert(roman, count-1) && convert(roman, count) == convert(roman, count+1)){
if (convert(roman,count) == 1 || convert(roman,count) == 10 || convert(roman,count) == 100 || convert(roman,count) == 1000)
if(convert(roman, count-1) == convert(roman, count-2) || convert(roman, count+1) == convert(roman, count+2)){
cout << "Error Try again" << endl;
return false;
}
else if (convert(roman,count) == 5 || convert(roman,count) == 50 || convert(roman,count) == 500){
cout << "Error Try again" << endl;
return false;
}
else return true;
}
}
return true;
}
int toDecimal(string s, bool*(checker) (string roman)){
/**map<char, int> roman;
roman['M'] = 1000;
roman['D'] = 500;
roman['C'] = 100;
roman['L'] = 50;
roman['X'] = 10;
roman['V'] = 5;
roman['I'] = 1;*/
checker(s);
int res = 0;
for (int i = 0; i < s.length() - 1; ++i){
int num = convert(s,i);
res += num;
/**if (roman[s[i]] < roman[s[i+1]])
res -= roman[s[i]];
else
res += roman[s[i]];
}
res += roman[s[s.size()-1]];*/}
return res;
}
int convert(string roman, int i){
enum romans {I = 1, V = 5, X = 10, L = 50, C = 100, D = 500, M = 1000};
int num = 0;
char c = roman[0];
switch(c){
case 'M':
num = M; break;
case 'D':
if(i + 1 != roman.size() && roman[i+1] == 'M'){
num = M - D;break;
}
else
num = D; break;
case 'C':
if(i + 1 != roman.size() && roman[i+1] == 'M' || roman[i+1] == 'D'){
if(roman[i+1] == 'M') num = M - C; break;
if(roman[i+1] == 'D') num = D - C; break;
}
else
num = C; break;
case 'L':
if(i + 1 != roman.size() && roman[i+1] == 'M' || roman[i+1] == 'D' || roman[i+1] == 'C'){
if(roman[i+1] == 'M') num = M - L; break;
if(roman[i+1] == 'D') num = D - L; break;
if(roman[i+1] == 'C') num = C - L; break;
}
else
num = L; break;
case 'X':
if(i + 1 != roman.size() && roman[i+1] == 'M' || roman[i+1] == 'D' || roman[i+1] == 'C'|| roman[i+1] == 'L'){
if(roman[i+1] == 'M') num = M - X; break;
if(roman[i+1] == 'D') num = D - X; break;
if(roman[i+1] == 'C') num = C - X; break;
if(roman[i+1] == 'L') num = C - X; break;
}
num = X; break;
case 'V':
if(i + 1 != roman.size() && roman[i+1] == 'M' || roman[i+1] == 'D' || roman[i+1] == 'C'|| roman[i+1] == 'L' || roman[i+1] == 'X'){
if(roman[i+1] == 'M') num = M - V; break;
if(roman[i+1] == 'D') num = D - V; break;
if(roman[i+1] == 'C') num = C - V; break;
if(roman[i+1] == 'L') num = L - V; break;
if(roman[i+1] == 'X') num = X - V; break;
}
num = V; break;
case 'I':
if ( i + 1 != roman.size() && roman[i + 1] != 'I'){
if(roman[i+1] == 'M') num = M - I; break;
if(roman[i+1] == 'D') num = D - I; break;
if(roman[i+1] == 'C') num = C - I; break;
if(roman[i+1] == 'L') num = L - I; break;
if(roman[i+1] == 'X') num = X - I; break;
}
num =1; break;
}
return num;
}
** I have added the help of people on here. This is an edit to show an progress/congress.
This is the code that I use to convert Roman (smaller than 3999) to Integer. You may check if it works for larger numbers.
int romanToInt(string s) {
map<char, int> roman;
roman['M'] = 1000;
roman['D'] = 500;
roman['C'] = 100;
roman['L'] = 50;
roman['X'] = 10;
roman['V'] = 5;
roman['I'] = 1;
int res = 0;
for (int i = 0; i < s.size() - 1; ++i)
{
if (roman[s[i]] < roman[s[i+1]])
res -= roman[s[i]];
else
res += roman[s[i]];
}
res += roman[s[s.size()-1]];
return res;
}
Hope this could help you.
The solution provided by Annie Kim works, but it uses a std::map, querying it several times for the same character, and I fail to see a reason for it.
int convert_roman_digit(char d)
{
switch (d)
{
case 'M': return 1000;
case 'D': return 500;
case 'C': return 100;
case 'L': return 50;
case 'X': return 10;
case 'V': return 5;
case 'I': return 1;
default: throw std::invalid_argument("Invalid digit");
}
}
int roman_to_int(const std::string& roman)
{
int result = 0, last_added = 0;
for (auto it = roman.rbegin(); it != roman.rend(); ++it)
{
const int value = convert_roman_digit(*it);
if (value >= last_added)
{
result += value;
last_added = value;
}
else
{
result -= value;
}
}
return result;
}
Caveat: the function happily accepts some invalid inputs (e.g. IMM) including "negative" numbers (e.g. IIIIIIIIIIIIIX), there are no overflow checks, and it throws. Feel free to improve it.
int romanToInt(string s)
{
unordered_map<char, int> roman;
roman['I'] = 1;
roman['V'] = 5;
roman['X'] = 10;
roman['L'] = 50;
roman['C'] = 100;
roman['D'] = 500;
roman['M'] = 1000;
int num = 0, prev = 0, curr;
for (int i = s.length() - 1; i >= 0; i--)
{
curr = roman[s[i]];
num += (curr >= prev ? 1 : -1) * curr;
prev = curr;
}
return num;
}