I'm trying to write a function that takes 4 characters,with the first and third characters being numbers,and the second and fourth characters being operators,the function converts the the first and third characters into integers,and calculates the output based on the operator between them (or doesn't do that,if the operator stored in the fourth character has a higher priority).
This is my attempt:
#include <iostream>
#include<string>
using namespace std;
string calculate(char ch1,char ch2,char ch3,char ch4);
int main() {
int i = 1;
string input = "4/1+1-2*2" ;
string part;
int leng;
while(1){
char cha1 = input[i - 1];
char cha2 = input[i];
char cha3 = input[i + 1];
char cha4 = input[i + 2];
part = calculate(cha1,cha2,cha3,cha4);
if (part == "NULL") {
i += 2;
}
else{ input = input.replace((i-1),3,part); }
leng = input.size();
if (i == leng - 1) {
i = 1;
}
}
}
string calculate(char ch1, char ch2, char ch3, char ch4){
int in1;
int in3;
int result;
string part;
if (ch2 == '-') {
if (ch4 == '*') {
part = 'NULL';
}
else if (ch4 == '/') {
part = "NULL";
}
else {
in1 = stoi(ch1);
in3 = stoi(ch3);
result = in1 - in3;
part = to_string(result);
}
}
else if (ch2 == '+') {
if (ch4 == '*') {
part = "NULL";
}
else if (ch4 == '/') {
part = "NULL";
}
else {
in1 = stoi(ch1);
in3 = stoi(ch3);
result = in1 + in3;
part = to_string(result);
}
}
else if (ch2 == '*') {
if (ch4 == '*') {
part = "NULL";
}
else if (ch4 == '/') {
part = "NULL";
}
else {
in1 = stoi(ch1);
in3 = stoi(ch3);
result = in1 * in3;
part = to_string(result);
}
}
else if (ch2 == '/') {
if (ch4 == '*') {
part = "NULL";
}
else if (ch4 == '/') {
part = "NULL";
}
else {
in1 = stoi(ch1);
in3 = stoi(ch3);
result = in1 * in3;
part = to_string(result);
}
}
return part;
}
The program probably won't work as intended in it's current state,but I'll worry about that later,for now I want to deal with the stoi() function,because for every line that contains this function,I get the error in the title.
I want to know what I'm doing wrong,and what this error message exactly means to avoid getting it in the future.
Thank you in advance.
std::stoi expects a std::string as argument, but you are giving it a single char.
There is no direct conversion from char to std::string, so you need to be explicit about it:
stoi(string(1, ch1));
Here string(1, ch1) creates a string of length 1 containing only the character ch1.
Alternatively, if you are sure that ch1 is a digit at that point (stoi will throw if it isn't) you can simply subtract '0', since the digits are guaranteed to be correctly ordered in the character set:
ch1 - '0'
Or rather, you probably want to pass a std::string directly to your function, instead of multiple individual chars. You can use the .substr member function to get substrings from a string.
std::stoi takes a std::string as its argument, but you are giving it a char.
You can directly convert char's to ints via a cast like this:
int num = ch1 - '0';
(You may want to write a function to do this, and use proper c++ style casts)
Or, covert the char to a string, or use strings to start with
Example:
int main() {
char ch1 = '9';
int in1 = ch1 - '0';
std::cout << in1 << "\n";
}
Related
This question already has answers here:
What is causing the "error LNK2005: already defined in .obj" s errors in my code?
(1 answer)
What does this error mean and how do I solve it: error LNK2005: "<symbol>" already defined in <file.obj>
(1 answer)
Closed 2 months ago.
I'm trying to import a lightweight maths parsing library. It is only available as a .cpp file. (this is the library)
When I import it using #include mathparser.cpp, I get loads of LNK2005 errors, saying it is defining all the class methods again.
I'm not actually defining them in the main file though, why might these errors be occuring, and what should I do to fix them?
You should never #include a cpp file. You should include header files, and ensure they have header guards (or use #pragma once). In this case the mathparser.cpp should be split up such that the parser class is in its own header and cpp file, then just main is in the cpp file.
mathparser.h
#pragma once
#include < iostream >
#include < cstdlib >
#include < cctype >
#include < cstring >
#include < math.h >
#define PI 3.14159265358979323846
using namespace std;
enum types { DELIMITER = 1, VARIABLE, NUMBER, FUNCTION };
const int NUMVARS = 26;
class parser {
char *exp_ptr; // points to the expression
char token[256]; // holds current token
char tok_type; // holds token's type
double vars[NUMVARS]; // holds variable's values
void eval_exp1(double &result);
void eval_exp2(double &result);
void eval_exp3(double &result);
void eval_exp4(double &result);
void eval_exp5(double &result);
void eval_exp6(double &result);
void get_token();
public:
parser();
double eval_exp(char *exp);
char errormsg[64];
};
mathparser.cpp
#include "stdafx.h"
#include "mathparser.h"
// Parser constructor.
parser::parser()
{
int i;
exp_ptr = NULL;
for (i = 0; i < NUMVARS; i++)
vars[i] = 0.0;
errormsg[0] = '\0';
}
// Parser entry point.
double parser::eval_exp(char *exp)
{
errormsg[0] = '\0';
double result;
exp_ptr = exp;
get_token();
if (!*token)
{
strcpy(errormsg, "No Expression Present"); // no expression present
return (double)0;
}
eval_exp1(result);
if (*token) // last token must be null
strcpy(errormsg, "Syntax Error");
return result;
}
// Process an assignment.
void parser::eval_exp1(double &result)
{
int slot;
char temp_token[80];
if (tok_type == VARIABLE)
{
// save old token
char *t_ptr = exp_ptr;
strcpy(temp_token, token);
// compute the index of the variable
slot = *token - 'A';
get_token();
if (*token != '=')
{
exp_ptr = t_ptr; // return current token
strcpy(token, temp_token); // restore old token
tok_type = VARIABLE;
}
else {
get_token(); // get next part of exp
eval_exp2(result);
vars[slot] = result;
return;
}
}
eval_exp2(result);
}
// Add or subtract two terms.
void parser::eval_exp2(double &result)
{
register char op;
double temp;
eval_exp3(result);
while ((op = *token) == '+' || op == '-')
{
get_token();
eval_exp3(temp);
switch (op)
{
case '-':
result = result - temp;
break;
case '+':
result = result + temp;
break;
}
}
}
// Multiply or divide two factors.
void parser::eval_exp3(double &result)
{
register char op;
double temp;
eval_exp4(result);
while ((op = *token) == '*' || op == '/')
{
get_token();
eval_exp4(temp);
switch (op)
{
case '*':
result = result * temp;
break;
case '/':
result = result / temp;
break;
}
}
}
// Process an exponent.
void parser::eval_exp4(double &result)
{
double temp;
eval_exp5(result);
while (*token == '^')
{
get_token();
eval_exp5(temp);
result = pow(result, temp);
}
}
// Evaluate a unary + or -.
void parser::eval_exp5(double &result)
{
register char op;
op = 0;
if ((tok_type == DELIMITER) && *token == '+' || *token == '-')
{
op = *token;
get_token();
}
eval_exp6(result);
if (op == '-')
result = -result;
}
// Process a function, a parenthesized expression, a value or a variable
void parser::eval_exp6(double &result)
{
bool isfunc = (tok_type == FUNCTION);
char temp_token[80];
if (isfunc)
{
strcpy(temp_token, token);
get_token();
}
if ((*token == '('))
{
get_token();
eval_exp2(result);
if (*token != ')')
strcpy(errormsg, "Unbalanced Parentheses");
if (isfunc)
{
if (!strcmp(temp_token, "SIN"))
result = sin(PI / 180 * result);
else if (!strcmp(temp_token, "COS"))
result = cos(PI / 180 * result);
else if (!strcmp(temp_token, "TAN"))
result = tan(PI / 180 * result);
else if (!strcmp(temp_token, "ASIN"))
result = 180 / PI*asin(result);
else if (!strcmp(temp_token, "ACOS"))
result = 180 / PI*acos(result);
else if (!strcmp(temp_token, "ATAN"))
result = 180 / PI*atan(result);
else if (!strcmp(temp_token, "SINH"))
result = sinh(result);
else if (!strcmp(temp_token, "COSH"))
result = cosh(result);
else if (!strcmp(temp_token, "TANH"))
result = tanh(result);
else if (!strcmp(temp_token, "ASINH"))
result = asinh(result);
else if (!strcmp(temp_token, "ACOSH"))
result = acosh(result);
else if (!strcmp(temp_token, "ATANH"))
result = atanh(result);
else if (!strcmp(temp_token, "LN"))
result = log(result);
else if (!strcmp(temp_token, "LOG"))
result = log10(result);
else if (!strcmp(temp_token, "EXP"))
result = exp(result);
else if (!strcmp(temp_token, "SQRT"))
result = sqrt(result);
else if (!strcmp(temp_token, "SQR"))
result = result*result;
else if (!strcmp(temp_token, "ROUND"))
result = round(result);
else if (!strcmp(temp_token, "INT"))
result = floor(result);
else
strcpy(errormsg, "Unknown Function");
}
get_token();
}
else
switch (tok_type)
{
case VARIABLE:
result = vars[*token - 'A'];
get_token();
return;
case NUMBER:
result = atof(token);
get_token();
return;
default:
strcpy(errormsg, "Syntax Error");
}
}
// Obtain the next token.
void parser::get_token()
{
register char *temp;
tok_type = 0;
temp = token;
*temp = '\0';
if (!*exp_ptr) // at end of expression
return;
while (isspace(*exp_ptr)) // skip over white space
++exp_ptr;
if (strchr("+-*/%^=()", *exp_ptr))
{
tok_type = DELIMITER;
*temp++ = *exp_ptr++; // advance to next char
}
else if (isalpha(*exp_ptr))
{
while (!strchr(" +-/*%^=()\t\r", *exp_ptr) && (*exp_ptr))
*temp++ = toupper(*exp_ptr++);
while (isspace(*exp_ptr)) // skip over white space
++exp_ptr;
tok_type = (*exp_ptr == '(') ? FUNCTION : VARIABLE;
}
else if (isdigit(*exp_ptr) || *exp_ptr == '.')
{
while (!strchr(" +-/*%^=()\t\r", *exp_ptr) && (*exp_ptr))
*temp++ = toupper(*exp_ptr++);
tok_type = NUMBER;
}
*temp = '\0';
if ((tok_type == VARIABLE) && (token[1]))
strcpy(errormsg, "Only first letter of variables is considered");
}
main.cpp
#include "mathparser.h"
int main()
{
char expstr[256];
parser ob;
cout << "Math expression parser. Enter a blank line to stop.\n\n";
do
{
cout << "Enter expression: ";
cin.getline(expstr, 255);
double ans = ob.eval_exp(expstr);
if (*ob.errormsg)
cout << "Error: " << ob.errormsg << "\n\n";
else
cout << "Answer: " << ans << "\n\n";
} while (*expstr);
return 0;
}
Then in your code you can #include "mathparser.h" to instantiate the parser class for your purposes.
Note that this code itself is full of poor practices and therefore a bad reference to study for learning modern C++, but that is outside the scope of your current question.
I am working on my first web app (weather visualization) that requires some light c++ on the back end. I am using wget to download the raw text, and c++ console to parse the data and it then writes HTML. This works great so far.
METAR is basically raw weather data from a station. (Time, Date, Conditions, Temp etc). The one I am using currently is :
2018/08/10 08:09
KBAZ 100809Z AUTO 00000KT 10SM BKN012 26/23 A3002 RMK AO2 T02610233
I have been able to store each set of data into different variables. The set I am looking at with the issue is the "26/23" above, which is the temperature and dew point in Celsius.
So far I have a string called tempAndDewpoint with "26/23" stored in it... I am using substr(0,2) to return the just temperature in a new string called temperature. (since the first number is temperature). This works great.
My question is, what happens if the temperature is below 10, like 9? I could no longer use substring(0,2) because that would then return "9/" as the current temperature.
I hope to find some guidance with this that is not too complicated for me to duplicate. I wasn't even sure what to name this question as I am not sure what this issue is called. Surely it must be common?
Beware: Negative temperatures in METAR are prefixed with M. So these are valid temp groups: 5/M2 or M8/M12 (negative dew points are in fact icing points). So I would not use a custom parser here:
struct TTD {
short int t;
short int td;
bool parse(const char *tempAndDewpoint) {
const char *next;
t = parse_partial(tempAndDewpoint, &next);
if (*next != '/') return false;
td = parse_partial(next + 1, &next);
return (*next == '\0');
}
private:
static short int parse_partial(const char *beg, const char **next) {
bool neg = false;
short int val = 0;
if (*beg == 'M') {
neg = true;
beg += 1;
}
while (*beg >= '0' && *beg <= '9') {
val = val * 10 + (*beg - '0');
beg += 1;
}
*next = beg;
if (neg) val = -val;
return val;
}
};
The simple solution is to not store as a string at all. Split the string into two independent numbers. As stated in the other answer you do need to take care of "M" being a prefix for negative numbers but there is no read to parse the numbers by hand:
int parseNum(const std::string& str)
{
size_t pos;
int num;
if (!str.empty() && str.front() == 'M')
{
num = -std::stoi(str.substr(1), &pos);
if (pos != str.size() - 1)
{
throw std::invalid_argument("invalid input");
}
}
else
{
num = std::stoi(str, &pos);
if (pos != str.size())
{
throw std::invalid_argument("invalid input");
}
}
return num;
}
size_t slash = tempAndDewpoint.find("/");
if (slash == std::string::npos)
{
throw std::invalid_argument("invalid input");
}
int temp = parseNum(tempAndDewpoint.substr(0, slash));
int dew = parseNum(tempAndDewpoint.substr(slash + 1));
My code first of all:
int GetHighScore(string name)
{
int highScore = 0;
ifstream fin;
char textInFile[50];1
fin.open(name + ".txt", ios::in);
if (fin.fail())
{
// Old piece of code
highScore = 0;
}
else
{
while (fin.good())
{
fin >> textInFile;
for each (char var in textInFile)
{
if (var == '#')
{
char c = fin.peek();
if (c == '1')
{
char score = fin.peek();
highScoreLvl1 = (int)score;
}
else if (c == '2')
{
char score = fin.peek();
highScoreLvl2 = (int)score;
}
else if (c == '3')
{
char score = fin.peek();
highScoreLvl3 = (int)score;
}
}
}
}
//fin >> highScore;
}
// Return the high score found in the file
return highScoreLvl1;
}
It detects the '#', but then c gets assigned the value 'ÿ' when it performs the peek operation. What it should give is the number '1', '2' or '3' (in char form); but it doesn't for some reason, and I can't see why... :/
Here's what the file looks like:
level#12level#22level#32
The first number represents the level, and the second number is the score achieved on that level.
If your file contains the only string 'level#12level#22level#32' then it's read into textInFile in fin >> textInFile operator. When you meet '#' character in the string you're trying to peek character from the file stream but there is nothing to peek, that's why -1 (end of file) is returned.
To fix this you need to take next character from textInFile string, not from the file. Here is example code:
int GetHighScore(string name)
{
int highScore = 0;
ifstream fin;
char textInFile[50];
fin.open(name + ".txt", ios::in);
int highScoreLvl1, highScoreLvl2, highScoreLvl3;
if (fin.fail())
{
// Old piece of code
highScore = 0;
}
else
{
while (fin.good())
{
fin >> textInFile;
bool bPrevIsHash = false;
size_t nLength = strlen(textInFile);
for (size_t i = 0; i + 2 < nLength; ++i)
{
if (textInFile[i] == '#')
{
if (textInFile[i + 1] == '1')
{
highScoreLvl1 = (int)textInFile[i + 2];
}
else if (textInFile[i + 1] == '2')
{
highScoreLvl2 = (int)textInFile[i + 2];
}
else if (textInFile[i + 1] == '3')
{
highScoreLvl3 = (int)textInFile[i + 2];
}
}
}
}
}
// Return the high score found in the file
return highScoreLvl1;
}
And there are several other issues with your code:
You return value of highScoreLvl1 that could be left uninitialized because there can be no '#' in the string. And probably you mean to return max value of highScoreLvl1, highScoreLvl2 or highScoreLvl3.
You're assigning value of char converted to int. In this case you will not get value of 1, 2, etc. You'll get ordinal of ASCII character, e.g. 0x31 (49) for '1', 0x32 (50) for 2, etc. If you need digit value you can do following trick: highScoreLvl1 = textInFile[i + 2] - '0';
What would be the most efficient yet simplest way to convert a char to its unsigned binary representation (bytes where the MSB is 0)? I have a method set up like this:
string AsciiToBinary(char value) {
string binary = "";
int code = value;
while (code > 0) {
if ((code % 2) == 1) {
binary.append("1", 1);
} else {
binary.append("0", 1);
}
code = code / 2;
}
return binary;
}
I am assuming that setting an int to a char sets the char's ASCII value to the int. However, my results do not match the ASCII table. I am implementing this function as follows:
char head = stack.pop();
int code = head; // do not need to parse
string binary;
while (!stack.isEmpty()) {
binary = AsciiToBinary(code);
outfile << binary << endl;
binary.clear();
head = stack.pop();
code = head;
}
I have stored all of the chars in a stack.
Thank you for info and direction.
std::string::append() adds the character onto the end of the string. So you are putting the bits on in the reverse order: the LSB is the first character and vice versa. Try this: binary.insert (0, 1, (code % 2 == 1) ? '1' : '0');
This method works well and is editable for all those interested and learning C++:
using namespace std; // bad for updates
#include <string>
string AsciiToBinary(char value) {
string binary = "";
unsigned int code = value;
unsigned int chk = value;
while (code > 0) {
if ((code & 1) == 1) {
binary.append("1", 1);
} else {
binary.append("0", 1);
}
code = code / 2;
}
reverse(binary.begin(), binary.end());
if (chk < 64) {
binary.insert(0, "00");
} else {
binary.insert(0, "0");
}
return binary;
}
I was trying the Open Courseware CS106b assignment 1. I am getting stuck on problem 4 which requires the use of recursion to write an integer to string convertor. We are not allowed to use any library functions that perform integer conversions.
The problem is that after every 'recursion level' the code does not keep track of the previous string, thus I am not able to append and build-onto the string.
#include <iostream>
#include <string>
#include "console.h"
#include "simpio.h"
using namespace std;
/* Function prototypes */
string intToString(int n);
int stringToInt(string str);
/* Main program */
int main() {
// [TODO: fill in the code]
int n = getInteger("Enter number for conversion to String: ");
cout<< "Converted to String: "<<intToString(n);
return 0;
}
//Functions
string intToString(int n){
double toBeDecomposed = n;
string convertedToString;
char ch;
string tempString;
if((double)(toBeDecomposed/10) >= 0.1){
int lastDigit = (int)toBeDecomposed%10;
toBeDecomposed = (int)(toBeDecomposed/10);
intToString(toBeDecomposed);
if (lastDigit == 0) {
ch = '0';
}
else if (lastDigit == 1) {
ch = '1';
}
else if (lastDigit == 2) {
ch = '2';
}
else if (lastDigit == 3) {
ch = '3';
}
else if (lastDigit == 4) {
ch = '4';
}
else if (lastDigit == 5) {
ch = '5';
}
else if (lastDigit == 6) {
ch = '6';
}
else if (lastDigit == 7) {
ch = '7';
}
else if (lastDigit == 8) {
ch = '8';
}
else if (lastDigit == 9) {
ch = '9';
}
tempString = string() + ch;
convertedToString = convertedToString.append(tempString);
cout<<convertedToString<<endl;
}
cout<<"Returning: "<<convertedToString<<endl;
return convertedToString;
}
int stringToInt(string str){
return 0;
}
My debugging output shows that it only returns the last digit:
Can anyone suggest how to successfully append to the string ConvertedToString so that I return the whole converted integer?
You aren't doing anything with the result of your recursive function call.
The hint is that intToString returns a string. You're ignoring that return value when you call intToString(toBeDecomposed);.
Capture that return value and do something with it.
your convertedToString variable is a local varible, so every time intToString function call it create new one and when recursion end and return it gets the last convertedToString which contains the last digit.
simple solution is to make it static or global.