The code for this string calculator has no operator precedence and I am not too sure how to fix it. I am confident it has something to do with the switch statement but I need this string calculator to move from left to right and calculate no matter if multiplication occurs before subtraction/addition or not. Here is the code so far:
#include<iostream>
#include<sstream>
#include<string>
#include<cctype>
#include<cmath>
using namespace std;
enum {PLUS='+',MINUS='-',MULT='*'};
int numberValue(string &expr)
{
istringstream is(expr);
int value = 0;
is >> value;
return value;
}
int expressionValue(string &expr)
{
int i = 0;
int p = 0;
if(expr.at(0) == '(' && expr.at(expr.length()-1) == ')')
{
for(i=0;i<expr.length();i++)
{
if(expr.at(i)=='(')
p++;
else if(expr.at(i)==')')
p--;
if(p==0)
break;
}
if(i==expr.length()-1)
return expressionValue(expr.substr(1,expr.length()-2));
}
for(i=0;i<expr.length();i++)
{
if(expr.at(i)=='(')
p++;
else if(expr.at(i)==')')
p--;
else if(p==0 && ispunct(expr.at(i)))
{
switch(expr.at(i))
{
case PLUS:
return expressionValue(expr.substr(0,i)) +
expressionValue(expr.substr(i+1,expr.length()-i- 1));
case MINUS:
return expressionValue(expr.substr(0,i)) -
expressionValue(expr.substr(i+1,expr.length()-i-1));
case MULT:
return expressionValue(expr.substr(0,i)) *
expressionValue(expr.substr(i+1,expr.length()-i-1));
}
}
}
return numberValue(expr);
}
bool Validate(string inputStr)
{
for(int x = 0;x < inputStr.length(); x ++)
{
if((inputStr[x] == '+') || (inputStr[x] == '-'))
{
if((inputStr[x+1] == '+') || (inputStr[x+1] =='-'))
{
return false;
}
}
}
string arr = "0123456789+-*";
int count = 0;
for(int a = 0; a < inputStr.length(); a++)
{
for(int b = 0; b < arr.length(); b++)
{
if(inputStr[a] == arr[b])
{
count++;
}
}
}
if(count == inputStr.length())
{
return true;
}
else
{
return false;
}
}
int main()
{
string expressionString;
string retry = "y";
cout << "Enter an expression as a string...you can use addition, subtraction \nand multiplication."<< endl;
cout << "\nKeep in mind that this calculator does not accept decimals and the \nleading operand can not be negative." << endl;
cout << "\nOperands can have no more than 8 digits, each operator has the same \nprecedence, and each operator is left associative." << endl;
do
{
cout << "\nEnter an expression: ";
cin >> expressionString;
if(Validate(expressionString) == true)
{
cout << expressionValue(expressionString) << endl;
}
else
{
cout << "An error has occured in the input" << endl;
}
cout << "Press \"y\" to enter another expression or \"n\" if you want to quit." << endl;
cin >> retry;
}while
(retry == "y");
return 0;
}
I've identified two problems with your code.
First, and easier to fix. Cin >> string will only take everything up to the first whitespace character. It might be worth considering http://www.cplusplus.com/reference/istream/istream/getline/ which will take everything up to the newline character. This will stop your program from just returning '1' if you type '1 + 1'
Your second problem, and the one I think you are more interested in, is the fact that you've accidentally made your operators right-associative. This is a consequence of the way your program is recursing. If you think about the way your function is calling itself for the statement 1 + 2 * 3. When it encounters the first + it calls ExpressionValue('1') + ExpressionValue(2 * 3). Because of this the multiplication will be evaluated before the addition in that case.
The easiest way to solve that problem will probably be to just parse the string backwards, but I suspect that will require changing the code that handles your parentheses quite a bit.
On a somewhat unrelated note. On the style side of things, some of your code was kind of hard to read because you don't indent the interiors of functions.
Related
I'm doing a calculator in replit. Why does my cin.peek() == '\n' work when I enter + and - but it doesn't work when I enter *, /, or ^?
#include <iostream>
#include <math.h>
#include <vector>
#include <istream>
using namespace std;
float hasil;
vector<float> num;
vector<char> op;
void calc(float x, float y, char z) {
if (z == '+') {
hasil = x + y;
}
else if (z == '-') {
hasil = x - y;
}
else if (z == '*') {
hasil = x * y;
}
else if (z == '/') {
hasil = x / y;
}
else if (z == '^') {
hasil = pow(x,y);
}
else {
cout<< "wrong operator";
}
}
void input () {
float in;
char ch;
for (int i = 0;;i++) {
if(cin.peek() == '\n') {
break;
}
else if(cin.peek() == '+') {
op.push_back('+');
}
else if(cin.peek() == '-') {
op.push_back('+');
}
else if(cin.peek() == '*') {
op.push_back('*');
}
else if(cin.peek() == '/') {
op.push_back('/');
}
else if(cin.peek() == '^') {
op.push_back('^');
}
cin >> in;
num.push_back(in);
}
for (auto i = num.begin(); i != num.end(); ++i) {
cout << *i << " ";
}
for (auto i = op.begin(); i != op.end(); ++i) { //this is just so I can see what is in the vectors
cout << *i << " ";
}
calc(num.at(0),num.at(1),op.at(0));
for (int i = 2; i < num.size(); i++)
calc(hasil,num.at(i),op.at(i-1));
}
int main() {
cout << "rumus = ";
input();
cout << " = ";
cout << hasil;
}
When I enter 1+2+3+4 it works fine, but the for loop doesn't break when I, for example, enter 1/3 or 2/3.
if(cin.peek() == '\n') {
break;
}
Why doesn't this run when there is a /, *, or ^ in what I enter?
Sorry if I have bad grammar. English is not my first language, and I am very new to C++ and coding in general. I don't know much about coding.
If you enter "4-2", you might notice that the numbers are 4 and -2, and the operator is +.
It produces the correct result by mistake because of if(cin.peek() == '-') { op.push_back('+'). (Copy-paste bug?)
You never actually read an operator, you only read floats.
"+2" and "-2" are valid inputs when reading a number, and peek leaves the character in the stream.
Thus, "1+2" is read as "1" and "+2", "1-2" as "1" and "-2".
None of the other operators can prefix a number, so in all those cases the stream enters an error state, never reads anything, and you're stuck in a loop.
I will leave fixing the bug as an exercise.
I'm quite new to C++, so I apologize if I am not sounding technical. I am having a little trouble getting a multiple input and output with my code, I'm thinking I should have a loop to get the data but i'm not sure how i'd go about that in my code, I've thought about using getline() but that doesn't seem to want to work with Char.
I've tried getline but I'm not sure how to implement it with the Char input, I believe I may need a separate loop as well but again not too sure. I'm thinking it could be done to EoF as well.
Here's my code:
int main()
{
char inpval;
int outval = 0;
cout << "Enter a Roman Number to convert: " << endl;
while (cin.get(inpval))
{
inpval = toupper(inpval);
if (inpval == 'M')
outval = outval + 1000;
else if (inpval == 'D') {
inpval = cin.peek();
inpval = toupper(inpval);
if (inpval == 'M') {
outval = outval - 500;
continue;
} else {
outval = outval + 500;
continue;
}
}
//etc
cout << "The Equivalent Arabic value is:" << endl;
cout << outval << "\n";
return 0;
}
My expected output is:
(All on newline)
Input:
I
II
IV
V
VI
Output:
1
2
4
5
6
Actual output is:
Input:
I
Output:
1
P.S: The program converts Roman Numeral chars to their respected number.
Any help is appreciated!
You can take input multiple items from cin, using below syntax.
cin >> a;
cin >> b;
cin >> c;
Another way is also there
cin >> a >> b >> c;
This technique is called "operator chaining" which is similar to the above.
Do you have any problem doing it like this?
cout << "Enter a Roman Numeral" << endl;
string inpval;
cin >> inpval;
while (inpval != "exit")
{
int outval = 0;
if (inpval == "I")
outval = 1;
else if (inpval == "II")
outval = 2;
else if (inpval == "III")
outval = 3;
else if (inpval == "IV")
outval = 4;
// ect
cout << "The Equivalent Arabic value is: " << outval << endl << endl;
cout << "Enter next numeral: (type exit to exit) " << endl;
cin >> inpval;
}
Method 1: Use getchar(), Calculate/Convert Roman to integer until you encounter a space ' ',when you get a space ' ' output the integer and do the same next roman number until you get another space ' ' or newline '\n' and stop the program once you encounter newline '\n'.
Method 2:Use type std::string and take input with getline. Then iterate through the string and calculate until you find space ' ' output the number, do the same till you find next space ' ' or end when string ends.
If you know # of Roman numbers you want to convert you can put it in a loop.
Hope this helps.
Example(Method 2)
#include <bits/stdc++.h>
int value(char r)
{
if (r == 'I')
return 1;
if (r == 'V')
return 5;
if (r == 'X')
return 10;
if (r == 'L')
return 50;
if (r == 'C')
return 100;
if (r == 'D')
return 500;
if (r == 'M')
return 1000;
return -1;
}
int main()
{
int out=0;
std::string s;
std::string::iterator i; //string iterator
//for more info go to https://www.geeksforgeeks.org/stdstring-class-in-c/
getline(std::cin,s);
for (i = s.begin(); i!= s.end() ; ++i)
{
if(*i != ' ')//Encounter a space, output result and
{ //go to next roman numeral
int s1 = value(*i);
if (*(i+1) != ' ' || *(i+1) != '\0')
{
// Getting value of i+1 nth Element
int s2 = value(*(i+1));
// Comparing both values
if (s1 >= s2)
{
// Value of current symbol is greater
// or equal to the next symbol
out = out + s1;
}
else
{
out = out + s2 - s1;
i++; // Value of current symbol is
// less than the next symbol
}
}
else
{
out = out + s1;
i++;
}
}
else
{
std::cout<<out<<" ";
out = 0;
}
}
std::cout<<out<<" ";
std::cout<<std::endl;
return 0;
}
Input:
I II MM MCMIV
Output:
1 2 2000 1904
I'm trying to take user inputted notes and store them in an array. The validation works fine but when I input the last value in the loop I get:
Debug Assertion Failed!
Expression: "(_Ptr_user & (_BIG_ALLOCATION_ALIGNMENT - 1))==0"&&0
An invalid parameter was passed to a function that considers invalid parameters fatal.
I'm struggling to understand where the issue is and how I can fix it.
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
typedef string noteName;
noteName getNoteName(int i)
{
bool flag = true;
noteName Namein;
do
{
cout << "Please enter note name no. " << i + 1 << ": ";
cin >> Namein;
cout << "------------------------------------\n";
if (Namein.length() > 3 || Namein.length() < 2)
{
cout << "Sorry, a note name must be 2 or 3 characters long. Please try again.\n";
flag = false;
}
else if (Namein.length() == 3 && Namein[1] != '#')
{
cout << "Sorry, the second character of a sharp note name must be #. Please try again.\n";
flag = false;
}
else if ((Namein[0] < 'a' || Namein[0] > 'g') && (Namein[0] < 'A' || Namein[0] > 'G'))
{
cout << "Sorry, the first character of a note name must be a letter between A and G. Please try again.\n";
flag = false;
}
else if (isdigit(Namein.back()) == false)
{
cout << "Sorry, the last character of a note name must be a number. Please try again.\n";
flag = false;
}
else
{
flag = true;
}
} while (flag == false);
return Namein;
}
int main()
{
const int numNotes = 4;
noteName NoteNames[numNotes];
cout << "Hello\n";
for (int i = 0; i <= numNotes; i++)
{
NoteNames[i] = getNoteName(i);
}
cout << "Thank you, the note names and lengths you entered were: \n\n";
for (int i = 0; i <= numNotes; i++)
{
cout << i << ". " << NoteNames[i] << "\n";
}
cout << "Done!";
return 0;
}
I want to say it's something to do with getNoteName() having a string return type as I haven't had this issue with any of my other functions that return int.
noteName NoteNames[numNotes]; defines an array where NoteNames[numNotes - 1] is the largest element you can access.
You go one further than this. The behaviour on doing that is undefined which is manifesting itself as the crash that you observe.
Replace your loop limits with for (int i = 0; i < numNotes; i++), or similar.
(You also have your CamelCase conventions for class names and variable names switch round from what's normal, which makes your code confusing to read.)
(I'd also rather see constexpr int numNotes = 4;: Google that for more details.)
#include <iostream>
#include <string>
#include <queue>
#include <stack>
#include "NodeType.h"
using namespace std;
// Test if token is an operator
bool isOperator(char token);
int getPrecedence(char token);
bool comparePrecedence(char tokenA, char tokenB);
int main()
{
stack<char> tokenStack;
queue<char> tokenQueue;
string expression= "", postfix= "";
char x;
cout<<"Please enter a mathematical expression: "<<endl;
getline(cin, expression);
cout<<expression.length()<<endl;
for(int i = 0; i <= expression.length(); i++)
{
x = expression[i];
if(isdigit(x))
{
tokenQueue.push(x);
}
if(isOperator(x))
{
while((!tokenStack.empty()) && (comparePrecedence(x, tokenStack.top() == true)))
{
char z = tokenStack.top();
tokenQueue.push(z);
tokenStack.pop();
}
tokenStack.push(x);
}
if(x == '(')
{
tokenStack.push(x);
}
if(x == ')')
{
while((!tokenStack.empty()) && (tokenStack.top() != '('))
{
char z = tokenStack.top();
tokenQueue.push(z);
tokenStack.pop();
}
tokenStack.pop();
}
while(!tokenStack.empty())
{
char z = tokenStack.top();
tokenQueue.push(z);
tokenStack.pop();
}
}
return 0;
}
int getPrecedence(char token)
{
if((token == '+') || (token == '-'))
{
return 1;
}
else if((token == '*') || (token == '/'))
{
return 2;
}
else if ((token == '(') || (token == ')'))
return 0;
else
return 99;
}
// Test if token is an operator
bool isOperator(char token)
{
return token == '+' || token == '-' ||
token == '*' || token == '/';
}
bool comparePrecedence(char tokenA, char tokenB)
{
if(getPrecedence(tokenA) < getPrecedence(tokenB))
return true;
else
return false;
}
For some reason I cannot get my code to work correctly. It always throws a
Thread 1: EXC_BAD_ACCESS (code=EXC_1386_GPFLT) error. It is also not correctly placing the '+' sign when I test using a simple string such as: (3+4).
The Queue should look like: 34+ but it hold 3+4. It seems to me that the '+' operator never gets pushed onto the stack. Can anyone please help me find what I should be focussing my attention on?
Debugging code is a valuable skill to learn, it's my opinion that it should form a much more important part of curricula in schools.
For example, if you modify your code to output all the stack and queue operations thus:
int main()
{
stack<char> tokenStack;
queue<char> tokenQueue;
string expression= "", postfix= "";
char x;
cout<<"Please enter a mathematical expression: "<<endl;
getline(cin, expression);
cout<<expression.length()<<endl;
for(int i = 0; i <= expression.length(); i++)
{
x = expression[i];
if(isdigit(x))
{
tokenQueue.push(x);
cout << "qpush A " << x << '\n';
}
if(isOperator(x))
{
while((!tokenStack.empty()) && (comparePrecedence(x, tokenStack.top() == true)))
{
char z = tokenStack.top();
tokenQueue.push(z);
cout << "spop G " << z << '\n';
cout << "qpush B " << z << '\n';
tokenStack.pop();
}
tokenStack.push(x);
cout << "spush E " << x << '\n';
}
if(x == '(')
{
tokenStack.push(x);
cout << "spush F " << x << '\n';
}
if(x == ')')
{
while((!tokenStack.empty()) && (tokenStack.top() != '('))
{
char z = tokenStack.top();
tokenQueue.push(z);
cout << "spop H " << z << '\n';
cout << "qpush C " << z << '\n';
tokenStack.pop();
}
cout << "spop I " << tokenStack.top() << '\n';
tokenStack.pop();
}
while(!tokenStack.empty())
{
char z = tokenStack.top();
tokenQueue.push(z);
cout << "spop J " << z << '\n';
cout << "qpush D " << z << '\n';
tokenStack.pop();
}
}
return 0;
}
and run it with a simple 3+4, you'll see the following output:
qpush A 3
spush E +
spop J +
qpush D +
qpush A 4
So you are placing the operation on the stack. However, you later take it off the stack and put it on the queue before you place the next digit on the queue.
That's definitely the wrong order but, if you examine the code, it's not just a small snippet that has two lines in the wrong order (that would be too easy).
The code that's doing that transfer from stack to queue is the final while loop in main() which, after every single character, transfers all the items from the stack to the queue, effectively rendering your stack superfluous.
That's where you should be looking but I'll give you a clue. You don't want to be transferring stack to queue after every character, only for those that involve numbers.
There may well be other problems after you solve that one but that method (debugging output every time you do something important) should be able to give you enough information to fix whatever comes along.
When I run my program, I have to type how many rows do I want in my output. I have a limit from 1 to 100 rows. Each row is a task with a name of the task followed by increasing number, example: Task1:, Task2, .... When I type something into input, it must convert input string /see the code below - except the code in main();/.
My problem is that when I type first input, it should go to next task/next row/ but it doesnt. I type for example 10 strings but they dont go each to next task but they stay in one task..hope you understand now.
#include<iostream>
#include<string>
#include <ctype.h>
using namespace std;
void Convert(string input){
string output = "";
string flag = "";
bool underscore = false;
bool uppercase = false;
if ( islower(input[0]) == false){
cout << "Error!" <<endl;
return;
}
for (int i=0; i < input.size(); i++){
if ( (isalpha( input[i] ) || (input[i]) == '_') == false){
cout << "Error!" <<endl;
return;
}
if (islower(input[i])){
if (underscore){
underscore = false;
output += toupper(input[i]);
}
else
output += input[i];
}
else if (isupper(input[i])){
if (flag == "C" || uppercase){
cout << "Error!"<<endl;
return;
}
flag = "Java";
output += '_';
output += tolower(input[i]);
}
else if (input[i] == '_'){
if (flag == "Java" || underscore){
cout << "Error!" <<endl;
return;
}
flag = "C";
underscore = true;
}
}
cout << output <<endl;
}
int main(){
const int max = 100;
string input;
int pocet_r;
cout << "Zadaj pocet uloh:" << endl;
cin >> pocet_r;
if(pocet_r >= 1 && pocet_r <=100)
{
for (int i = 0; i <pocet_r; i++)
{
cout << "Uloha " << i+1 << ":" << endl;
while (cin >> input)
Convert (input);
while(input.size() > max)
cout << "slovo musi mat minimalne 1 a maximalne 100 znakov" << endl;
while(input.size() > max)
cin >> input;
while (cin >> input)
Convert(input);
}
}else{
cout << "Minimalne 1 a maximalne 100 uloh" << endl;
}
system("pause");
}
Your first if in Convert will always fail on a non-underscore and return. I don't think that's what's intended. Agree with other answer on the while cin loop. The next two whiles should be if's apparently. Step thru this code with a debugger and watch it line by line and see where it fails. You've got multiple issues here, and I'm not entirely sure what the intent is.
Edit - I didn't parse the extra parenthesis correctly. The first if in convert is actually okay.