Converting Roman Numerals to Int - Getting the Wrong Output - Why? - c++

Here is my code. First, I want to say, I have been experimenting, so if you see unnecessary variables here and there, that's why. But the main part of my code is in the function decimal in my class romanType. When I input certain roman numerals, I am not getting the exact numbers I want and it might be in my logic somewhere in my if/else statements.
By the way, to show how I traverse the string - I do it by reverse traversing. I go from the very end of the string to the very beginning of the string, which I think is easier with roman numerals. By the way, I also made an enum type so I could compare the roman numerals seeing which one is lesser, which one is greater etc. Then I used a map to be able to compare the enum values with the char value.
So the problem: For instance, when I type in CCC, I get 290 instead of 300. If you know what is wrong in my logic, I would greatly appreciate that! Thank you.
Furthermore, I am quite new to programming and would greatly appreciate any stylistic tips or anything I can learn about classes etc that I missed in writing this code? Please let me know what is best. Thank you.
#include <iostream>
#include <string>
#include <map>
using namespace std;
class romanType {
string numeral;
int k;
public:
romanType();
void rnumeral (string b) {numeral = b;}
int decimal(string num, char b, int temp) {
num = "";
enum RomanNumerals {I, V, X, L, C, D, M };
map<char, RomanNumerals> m;
m['I'] = I;
m['V'] = V;
m['X'] = X;
m['L'] = L;
m['C'] = C;
m['D'] = D;
m['M'] = M;
RomanNumerals roman1;
RomanNumerals roman2;
cout << "Please type in your roman numeral:" ;
cin >> num;
for (int i =0; i <num.length()-1; i++){
}
for(long i = num.length()-1; i>=0; i--)
{
b = num[i];
if (islower(b)) b=toupper(b);
roman1 = m[num[i]];
roman2 = m[num[i-1]];
switch(b){
case 'I':
if(num[i] == num.length()-1){
temp += 1;
}
break;
case 'V':
if(roman1 > roman2){
temp += 4;
continue;
}
else {
temp += 5;
}
break;
case 'X':
if(roman1 > roman2){
temp += 9;
continue;
}
else {
temp += 10;
}
break;
case 'L' :
if(roman1 > roman2){
temp += 40;
continue;
}
else {
temp += 50;
}
break;
case 'C':
if(roman1 > roman2){
temp += 90;
continue;
}
else {
temp += 100;
}
break;
case 'D' :
if(roman1 > roman2){
temp += 400;
continue;
}
else {
temp += 500;
}
break;
case 'M':
if(roman1 > roman2){
temp += 900;
continue;
}
else {
temp += 1000;
}
break;
}
}
return temp;
}
};
romanType::romanType () {
numeral = "";
}
int main() {
string k = "";
char b = ' ';
int temp = 0;
romanType type;
type.rnumeral(k);
int c = type.decimal(k, b, temp);
cout << c;
return 0;
}
EDIT: _____________________________________________________________________________
I found the solution to my problem. Here is my new code:
#include <iostream>
#include <string>
#include <map>
using namespace std;
string acceptRN();
class romanType {
string numeral;
int temp2;
int l;
// VARIABLES
public:
romanType();
//DEFAULT CONSTRUCTOR
void getRnumeral (string b)
{
numeral = b;
}
//SETTER
void decimal(string num, int temp, char b) {
num = numeral;
enum RomanNumerals {I, V, X, L, C, D, M };
map<char, RomanNumerals> m;
m['I'] = I;
m['V'] = V;
m['X'] = X;
m['L'] = L;
m['C'] = C;
m['D'] = D;
m['M'] = M;
RomanNumerals roman1;
RomanNumerals roman2;
RomanNumerals roman3;
for(long i = num.length()-1; i>=0; i--)
{
b = num[i];
if (islower(b)) b=toupper(b);
roman1 = m[num[i]];
roman2 = m[num[i-1]];
roman3 = m[num[i+1]];
switch(b){
case 'I':
if( roman3 > roman1 && i != num.length()-1){
continue;
}
else {
temp += 1;
break;
}
case 'V':
if(roman1 > roman2 && i != 0){
temp += 4;
continue;
}
else {
temp += 5;
}
break;
case 'X':
if( roman3 > roman1 && i != num.length()-1)
continue;
if(roman1 > roman2 && i!= 0){
temp += 9;
continue;
}
else {
temp += 10;
}
break;
case 'L' :
if(roman1 > roman2 && i!= 0){
temp += 40;
continue;
}
else {
temp += 50;
}
break;
case 'C':
if( roman3 > roman1 && i != num.length()-1)
continue;
if(roman2 == X && i!= 0){
temp += 90;
continue;
}
else {
temp += 100;
}
break;
case 'D' :
if(roman2 == C && i!= 0){
temp += 400;
continue;
}
else {
temp += 500;
}
break;
case 'M':
if(roman2 == C && i!= 0){
temp += 900;
continue;
}
else {
temp += 1000;
}
break;
}
}
temp2 = temp;
}
void showDecimal() {
cout << "Here is your roman numeral in decimal format:";
cout << temp2 << " \n \n \n";
}
};
romanType::romanType () {
numeral = "";
}
int main() {
string k = acceptRN();
int m = 0;
char l= ' ';
romanType type;
type.getRnumeral(k);
type.decimal(k, m, l);
type.showDecimal();
return 0;
}
string acceptRN(){
string num = "";
cout << "Please type in your roman numeral:" ;
cin >> num;
return num;
}

When I done the stuff from my comment and tweaked your code a bit I got this:
//---------------------------------------------------------------------------
int roman_ix[256]={-1};
const int roman_val[]={ 1 , 5 ,10 ,50 ,100,500,1000,0};
const char roman_chr[]={'I','V','X','L','C','D', 'M',0};
//---------------------------------------------------------------------------
int roman2int(char *s)
{
int i,x=0,v=0,v0;
// init table (just once)
if (roman_ix[0]<0)
{
for (i=0;i<256;i++) roman_ix[i]=0;
for (i=0;roman_chr[i];i++) roman_ix[roman_chr[i]]=i;
}
// find end of string
for (i=0;s[i];i++);
// proccess string in reverse
for (i--;i>=0;i--)
{
v0=v; // remember last digit
v=roman_val[roman_ix[s[i]]]; // new digit
if (!v) break; // stop on non supported character
if (v0>v) x-=v; else x+=v; // add or sub
}
return x;
}
//---------------------------------------------------------------------------
I tested on these:
1776 1776 MDCCLXXVI
1954 1954 MCMLIV
1990 1990 MCMXC
2014 2014 MMXIV
300 300 CCC
first number is converted from string, second is what it should be and last is the roman string.
If 256 entry table is too big you can shrink it to range A-Z which is significantly smaller but that require one more substraction in the code. It can be also hardcoded to get rid of the initialization:
//---------------------------------------------------------------------------
int roman2int(char *s)
{
// init
int i,x=0,v=0,v0; // A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
const int val['Z'-'A'+1]={ 0, 0, 100, 500, 0, 0, 0, 0, 1, 0, 0, 50, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 10, 0, 0 };
// find end of string
for (i=0;s[i];i++);
// process string in reverse
for (i--;i>=0;i--)
{
if ((s[i]<'A')||(s[i]>'Z')) break; // stop on non supported character
v0=v; v=val[s[i]-'A'];
if (v0>v) x-=v; else x+=v;
}
return x;
}
//---------------------------------------------------------------------------
As I got rid of your temp and roman1,roman2 and the switch if/else conditions and the code worked from the first compilation ... I am assuming that you are doing something fishy with them (got lost in the if/else combinations missing some edge case).

Related

Write a C++ program to find kernel in boolean expression

I am a college student, and I have a programming assignment asked us to find kernels in boolean expression. The document teacher provide has a sample pseudo code to guide us how to write a program. The pseudo code is as below.
// Kernel Algorithm
FindKernels(cube-free SOP expression F) // F: input Boolean function
{
K = empty; // K: list of kernel(s)
for(each variable x in F)
{
if(there are at least 2 cubes in F that have variable x)
{
let S = {cubes in F that have variable x in them};
let co = cube that results from intersection of all cubes
in S, this will be the product of just those literals that appear in
each of these cubes in S;
K = K ∪ FindKernels(F / co);
}
}
K = K ∪ F ;
return( K )
}
But I don.t know what is the meaning of the definition of "co". As what I understand S is those terms that have the variable X. Take "abc + abd + bcd = b(ac + ad + cd)" for example, S = {abc, abd, bcd}. But what is co??
I also write another program
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <iomanip>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
void find_kernels(vector<string> &terms);
bool eliminate_char(string &doing, char eliminate);
void eliminate_char_complete(vector<string> &terms, char eliminate);
int main()
{
string file_name;
vector<string> expression;
vector<string> expression_name;
string expression_temp, expression_name_temp, input_untruncated;
vector<vector<string>> terms;//break each expression into each term
here:
cout << "Please enter the file name that you want to load: ";
cin >> file_name;
ifstream load_file(file_name, ios::in);
if(!load_file)
{
cout << "The file you choose cannot be opened!\n";
goto here;
}
there:
cout << "Please enter the name of the output file: ";
cin >> file_name;
ofstream output_file(file_name, ios::out);
if(!output_file)
{
cout << "The file cannot be created!\n";
goto there;
}
while(load_file >> input_untruncated)
{
expression_name_temp = input_untruncated.substr(0, input_untruncated.find("="));
expression_temp = input_untruncated.substr(input_untruncated.find("=") + 1);
expression_name.push_back(expression_name_temp);
expression.push_back(expression_temp);
}
//start to truncate every terms
for(int i = 0 ; i < (int)expression.size() ; i++)
{
int j = 0;
int k = 0;//k >> last time location
vector<string> terms_temp_vector;
string terms_temp;
string expression_trans = expression[i];
while(j < (int)expression[i].size())
{
if(expression_trans[j] == '+' || expression_trans[j] == '-')
{
terms_temp = expression_trans.substr(k, j - k);
terms_temp_vector.push_back(terms_temp);
k = j + 1;
}
j++;
}
terms_temp = expression_trans.substr(k);
terms_temp_vector.push_back(terms_temp);
terms.push_back(terms_temp_vector);
}
/*for(int i = 0 ; i < (int)expression.size() ; i++)
{
cout << "expression_name: " << expression_name[i] << endl;
cout << expression[i] << endl;
cout << "terms: ";
for(int j = 0 ; j < (int)terms[i].size() ; j++)
{
cout << terms[i][j] << " ";
}
cout << endl;
}*/
cout << endl;
for(int i = 0 ; i < (int)expression.size() ; i++)
{
//output_file << expression_name[i] << endl;
//output_file << expression[i] << endl;
cout << "*";
while(terms[i].size() != 0)
{
find_kernels(terms[i]);
if(terms[i].size() != 0)
{
cout << "terms: ";
for(int j = 0 ; j < (int)terms[i].size() ; j++)
{
cout << terms[i][j] << " ";
}
cout << endl;
}
}
cout << endl;
}
/*for(int i = 0 ; i < (int)expression.size() ; i++)
{
cout << "expression_name: " << expression_name[i] << endl;
cout << expression[i] << endl;
cout << "terms: ";
for(int j = 0 ; j < (int)terms[i].size() ; j++)
{
cout << terms[i][j] << " ";
}
cout << endl;
}*/
return 0;
}
void find_kernels(vector<string> &terms)
{
int a = 0, b = 0, c = 0, d = 0, e = 0, g = 0;
for(int i = 0 ; i < (int)terms.size() ; i++)
{
string terms_temp = terms[i];
for(int j = 0 ; j < (int)terms_temp.size() ; j++)
{
switch(terms_temp[j])
{
case 'a':
a++;
break;
case 'b':
b++;
break;
case 'c':
c++;
break;
case 'd':
d++;
break;
case 'e':
e++;
break;
case 'g':
g++;
break;
}
}
}
int compare[] = {a, b, c, d, e, g};
int biggest = 0;
char eliminate;
for(int i = 0 ; i < 6 ; i++)
{
if(compare[i] > biggest)
{
biggest = compare[i];
}
}
if(biggest == 1)
{
terms.erase(terms.begin(), terms.end());
return;
}
if(biggest == a)
{
eliminate = 'a';
eliminate_char_complete(terms, eliminate);
}
if(biggest == b)
{
eliminate = 'b';
eliminate_char_complete(terms, eliminate);
}
if(biggest == c)
{
eliminate = 'c';
eliminate_char_complete(terms, eliminate);
}
if(biggest == d)
{
eliminate = 'd';
eliminate_char_complete(terms, eliminate);
}
if(biggest == e)
{
eliminate = 'e';
eliminate_char_complete(terms, eliminate);
}
if(biggest == g)
{
eliminate = 'g';
eliminate_char_complete(terms, eliminate);
}
}
bool eliminate_char(string &doing, char eliminate)
{
for(int i = 0 ; i < (int)doing.size() ; i++)
{
if(doing[i] == eliminate)
{
doing.erase (i, 1);
return 1;
}
}
return 0;
}
void eliminate_char_complete(vector<string> &terms, char eliminate)//delete unrelated terms
{
for(int i = 0 ; i < (int)terms.size() ; i++)
{
if(!eliminate_char(terms[i], eliminate))
{
terms.erase(terms.begin() + i);
}
}
}
input file be like
F1=ace+bce+de+g
F2=abc+abd+bcd
I don't obey the pseudo code above.
First, I break them into single terms and push them into a two dimention vector called terms.
terms[expression number][how many terms in one expression]
Second, I call find_kernels. The founction calculate every letters appear how many times in one expression. ps: only a, b, c, d, e, g will appear.
Third, take out the letter that appear the most time. ex: a, ab, abc...
Then, eliminate them in every terms of the same expression. If a terms do not have those letters, then delete the term directly.
Continue doing the same thing....
However, the question is that if F1 is abc+abd+bcd, I should output ac+ad+cd c+d a+c a+d, but my program will output ac+ad+cd only, cause abc+abd+bcd = b(ac+ad+cd) >> next round ac+ad+cd. a, c, d all apear twice, so there are deleted together. Nothing left.
Any suggestion to my code or further explination of the pseudo code will be appreciate. Thank you.
In general you should be clear about the problem you want to solve and the applied definitions. Otherwise you will always run into severe troubles.
Here you want to calculate the kernels of a boolean expression given in SOP (sum over products form, e.g., abc+cde).
A kernel of a boolean expression F is a cube-free expression that results when you divide F by a single cube.
That single cube is called a co-kernel. (This is the co in the pseudo code)
From a cube-free expression you cannot factor out a single cube that leaves behind no remainder.
Examples
F=ae+be+cde+ab
Kernel Co-Kernel
{a,b,cd} e
{e,b} a
{e,cd} b
{ae,be, cde, ab} 1
F=ace+bce+de+g
Kernel Co-Kernel
{a,b} c
{ac, bc, d} e
As you can see the co-kernel is the variable that you eliminate plus all other common variables that occur in the cubes containing the variable.
To implement that you apply this procedure now recursicely for each variable and store all kernel you create. Essentially thats all!
Practically, for an implementation I would propose to use some more handy encoding of the terms and not strings. As your input seems to only single letter variables you can map it to single bits in uint64 (or even uint32 when only lower case is considered). This will give an straight forward implementation like that (thought, it is optimzed for simplicity not performance):
#include <iostream>
#include <vector>
#include <string>
#inlcude <set>
void read_terms();
uint64_t parse_term(string sterm);
void get_kernels(vector<uint64_t>& terms, vector<pair<vector<uint64_t>, uint64_t> >& kernels);
string format_kernel(vector<uint64_t>& kernel);
int main()
{
read_terms();
return 0;
}
/*
Convert a cube into a string
*/
string cube_to_string(uint64_t cube) {
string res;
char ch = 'a';
for (uint64_t curr = 1; curr <= cube && ch <= 'z'; curr <<= 1, ch++) {
if ((curr & cube) == 0) {
continue;
}
res += ch;
}
ch = 'A';
for (uint64_t curr = (1<<26); curr <= cube && ch <= 'Z'; curr <<= 1, ch++) {
if ((curr & cube) == 0) {
continue;
}
res += ch;
}
return res;
}
/*
Convert a kernel or some other SOP expression into into a string
*/
string format_kernel(vector<uint64_t>& kernel) {
string res = "";
for (uint64_t k : kernel) {
string t = cube_to_string(k) + "+";
if (t.size() > 1) {
res += t;
}
}
if (res.size() > 0) {
res.resize(res.size() - 1);
}
return res;
}
/*
Queries the expression from the stdin and triggers the kernel calculcation.
*/
void read_terms() {
cout << "Please enter the terms in SOP form (0 to end input):" << endl;
vector<uint64_t> terms;
vector<pair<vector<uint64_t>, uint64_t> > kernels;
string sterm;
cout << "Term: ";
while (cin >> sterm) {
if (sterm == "0") {
break;
}
cout << "Term: ";
terms.push_back(parse_term(sterm));
}
get_kernels(terms, kernels);
set<string> set_kernels;
for (pair<vector<uint64_t>, uint64_t>k : kernels) {
set_kernels.insert(format_kernel(k.first));
}
for (string k : set_kernels) {
cout << k << endl;
}
return;
}
/*
Convert a term given as string into a bit vector.
*/
uint64_t parse_term(string sterm) {
uint64_t res = 0;
for (char c : sterm) {
if (c >= 'a' && c <= 'z') {
res |= 1ull << uint64_t(c - 'a');
}
else if (c >= 'A' && c <= 'Z') {
res |= 1ull << uint64_t(c - 'A' + 26);
}
}
return res;
}
/*
Returns a bitvector having a for a each variable occuring in one or more of the cubes.
*/
uint64_t get_all_vars(vector<uint64_t>& terms) {
uint64_t res = 0;
for (uint64_t t : terms) {
res |= t;
}
return res;
}
/*
Returns a bitvector having a one for each variable that is shared between all cubes.
*/
uint64_t get_common_vars(vector<uint64_t>& terms) {
if( terms.size() == 0 ) {
return 0ull;
}
uint64_t res = terms[0];
for (uint64_t t : terms) {
res &= t;
}
return res;
}
/*
Divides all set variables from the cubes and returns then in a new vector.
*/
void div_terms(vector<uint64_t>& terms, uint64_t vars, vector<uint64_t>& result) {
result.resize(terms.size());
uint64_t rvars = vars ^ ~0ull; //flip all vars
for (size_t i = 0; i < terms.size(); i++) {
result[i] = terms[i] & rvars;
}
}
/*
Core calculation to get the kernels out of an expression.
*/
void get_kernels(vector<uint64_t>& terms, vector<pair<vector<uint64_t>, uint64_t> >& kernels ) {
uint64_t vars = get_all_vars(terms);
for (uint64_t curr = 1; curr <= vars; curr <<= 1) {
if ((curr & vars) == 0) {
continue;
}
vector<uint64_t> curr_terms, curr_div_terms;
for (uint64_t uterm : terms) {
if ((uterm & curr) != 0ull) {
curr_terms.push_back(uterm);
}
}
if (curr_terms.size() > 1) {
uint64_t new_kernel = 0ull;
uint64_t new_co = get_common_vars(curr_terms); // calculate the new co-kernel
div_terms(curr_terms, new_co, curr_div_terms);//divide cubes with new co-kernel
kernels.push_back(pair<vector<uint64_t>, uint64_t>(curr_div_terms, new_co));
get_kernels(curr_div_terms, kernels);
}
}
}
Especially the elimination of kernels that occur several times is not very efficient, as it just happens at the end. Usually you would do this earlier and prevent multiple calculation.
This implementation takes the inputs from the stdin and writes the results to the stdout. So you might change it for using files when using it as your homework.
Thought other implementations like counting the number of occurences and making use out of that is also possible.

Overwrite the elements in a vector without specifying specific elements

I am making a calculator that accepts multiple operators at once. I have a vector pair that stores the position of operators, and the type of operator. The vector must be updated after each loop as the previous positions are no longer valid due to the result replacing a part of the input string.
I've attempted to use clear() so that it starts from the beginning again, but that results in Expression: vector iterators incompatible. I don't think I can use std::replace since the number of operators in the string changes after each loop. Is there a way to just have it start from the beginning again and overwrite any existing elements?
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
int main()
{
std::cout << "C++ Calculator" << std::endl;
while (true) //runs forever with loop
{
std::string input;
std::getline(std::cin, input);
//erases whitespace
int inp_length = input.length();
for (int i = inp_length - 1; i >= 0; --i)
{
if (input[i] == ' ')
input.erase(i, 1);
}
std::vector<std::pair<int, char>> oper_pvec;
int vec_pos = 0;
//finds the position of operators and type
for (std::string::iterator i = input.begin(); i != input.end(); ++vec_pos, ++i)
{
switch (*i)
{
case 'x':
{
oper_pvec.push_back(std::pair<int, char>(vec_pos, 'x'));
break;
}
case '/':
{
oper_pvec.push_back(std::pair<int, char>(vec_pos, '/'));
break;
}
case '+':
{
oper_pvec.push_back(std::pair<int, char>(vec_pos, '+'));
break;
}
case '-':
{
oper_pvec.push_back(std::pair<int, char>(vec_pos, '-'));
break;
}
}
}
//declarations before loop to make sure they're all able to be accessed, will probably change later
int loper_pos = 0; //must be set 0 since there's no left operator at first
int roper_pos;
double lnum; //left number
double rnum; //right number
char loper; //left operator
char roper; //right operator
int pos = -1; //position of loop, needs to be -1 since it increments it each time
std::string holder = input; //copy of input
auto op = oper_pvec.begin();
while (op != oper_pvec.end())
{
op = oper_pvec.begin();
++pos; //position of loop
int key = std::get<0>(*op); //gets first value from vector pair
char val = std::get<1>(*op); //gets second value from vector pair
//gets previous/next vector pairs
std::vector<std::pair<int, char>>::iterator prev_op = oper_pvec.begin();
std::vector<std::pair<int, char>>::iterator next_op = oper_pvec.end();
if (op != oper_pvec.begin()) prev_op = std::prev(op);
if (op != oper_pvec.end()) next_op = std::next(op);
//extracts the value of pairs
if (pos > 0)
{
loper_pos = std::get<0>(*prev_op);
loper = std::get<1>(*prev_op);
}
if (pos == oper_pvec.size() - 1) roper_pos = oper_pvec.size();
else
{
roper_pos = std::get<0>(*next_op);
roper = std::get<1>(*next_op);
}
//replaces numbers and etc with product, only multiplication for now
switch (val)
{
case 'x':
{
int lnum_start = loper_pos + 1;
if (loper_pos == 0) lnum_start = 0;
int lnum_len = key - (loper_pos + 1);
if (loper_pos == 0) lnum_len = key;
lnum = std::stod(input.substr(lnum_start, lnum_len));
int rnum_start = key + 1;
int rnum_len = (roper_pos - 1) - key;
rnum = std::stod(input.substr(rnum_start, rnum_len));
double prod = lnum * rnum;
std::string to_string = std::to_string(prod);
input.replace(loper_pos, roper_pos, to_string);
break;
}
}
/////////////////////////////////problem area////////////////////////////////////////
//clears the vector and then finds the operators again
oper_pvec.clear();
int vpos = 0;
for (std::string::iterator it = input.begin(); it != input.end(); ++vpos, ++it)
{
if (vpos == input.length())
{
vpos = 0;
break;
}
switch (*it)
{
case 'x':
{
oper_pvec.push_back(std::pair<int, char>(vpos, 'x'));
break;
}
case '/':
{
oper_pvec.push_back(std::pair<int, char>(vpos, '/'));
break;
}
case '+':
{
oper_pvec.push_back(std::pair<int, char>(vpos, '+'));
break;
}
case '-':
{
oper_pvec.push_back(std::pair<int, char>(vpos, '-'));
break;
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
}
//converts to double then prints on screen
double out = std::stod(input);
std::cout << out << std::endl;
}
}
Not really the answer to the title but instead of trying to overwrite the vector I just continued to use clear() and changed the while loop to oper_pvec.size() != 0.
(Full code since I had to change quite a few things to get it to work properly)
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
int main()
{
std::cout << "C++ Calculator" << std::endl;
while (true) //runs forever with loop
{
std::string input;
std::getline(std::cin, input);
//erases whitespace
int inp_length = input.length();
for (int i = inp_length - 1; i >= 0; --i)
{
if (input[i] == ' ')
input.erase(i, 1);
}
std::vector<std::pair<int, char>> oper_pvec;
int vec_pos = 0;
//finds the position of operators and type
for (std::string::iterator i = input.begin(); i != input.end(); ++vec_pos, ++i)
{
switch (*i)
{
case 'x':
{
oper_pvec.push_back(std::pair<int, char>(vec_pos, 'x'));
break;
}
case '/':
{
oper_pvec.push_back(std::pair<int, char>(vec_pos, '/'));
break;
}
case '+':
{
oper_pvec.push_back(std::pair<int, char>(vec_pos, '+'));
break;
}
case '-':
{
oper_pvec.push_back(std::pair<int, char>(vec_pos, '-'));
break;
}
}
}
//declarations before loop to make sure they're all able to be accessed, will probably change later
int loper_pos = 0; //must be set 0 since there's no left operator at first
int roper_pos;
double lnum; //left number
double rnum; //right number
char loper; //left operator
char roper; //right operator
int pos = -1; //position of loop, needs to be -1 since it increments it each time
std::string holder = input; //copy of input
std::vector<std::pair<int, char>> vec_copy = oper_pvec;
auto op = oper_pvec.begin();
while (oper_pvec.size() != 0)
{
op = oper_pvec.begin();
++pos; //position of loop
int key = std::get<0>(*op); //gets first value from vector pair
char val = std::get<1>(*op); //gets second value from vector pair
//gets previous/next vector pairs
std::vector<std::pair<int, char>>::iterator prev_op = oper_pvec.begin();
std::vector<std::pair<int, char>>::iterator next_op = oper_pvec.end();
if (op != oper_pvec.begin()) prev_op = std::prev(op);
if (op != oper_pvec.end()) next_op = std::next(op);
//extracts the value of pairs
if (pos > 0)
{
loper_pos = std::get<0>(*prev_op);
loper = std::get<1>(*prev_op);
}
if (op == oper_pvec.begin()) loper_pos = 0;
if (oper_pvec.size() == 1) roper_pos = input.length();
else
{
roper_pos = std::get<0>(*next_op);
roper = std::get<1>(*next_op);
}
//replaces numbers and etc with product, only multiplication for now
switch (val)
{
case 'x':
{
int lnum_start = loper_pos + 1;
if (lnum_start == 1) lnum_start = 0;
if (loper_pos > 0)
if (isdigit(input[loper_pos - 1])) lnum_start = 0;
int lnum_len = key - (loper_pos + 1);
if (lnum_start == 0)
{
if (key == 1) lnum_len = 1;
else lnum_len = key - 1;
}
lnum = std::stod(input.substr(lnum_start, lnum_len));
int rnum_start = key + 1;
int rnum_len = (roper_pos - 1) - key;
rnum = std::stod(input.substr(rnum_start, rnum_len));
double prod = lnum * rnum;
std::string to_string = std::to_string(prod);
input.replace(loper_pos, roper_pos, to_string);
break;
}
}
//clears the vector and then finds the operators again
oper_pvec.clear();
int vpos = 0;
for (std::string::iterator it = input.begin(); it != input.end(); ++vpos, ++it)
{
if (vpos == input.length())
{
vpos = 0;
break;
}
switch (*it)
{
case 'x':
{
oper_pvec.push_back(std::pair<int, char>(vpos, 'x'));
break;
}
case '/':
{
oper_pvec.push_back(std::pair<int, char>(vpos, '/'));
break;
}
case '+':
{
oper_pvec.push_back(std::pair<int, char>(vpos, '+'));
break;
}
case '-':
{
oper_pvec.push_back(std::pair<int, char>(vpos, '-'));
break;
}
}
}
}
//converts to double then prints on screen
double out = std::stod(input);
std::cout << out << std::endl;
}
}

Visual C++ assert- String subscript out of range

My program is a solution for the Day 6 question in Advent of Code 2015. I get an error when I use "Start Without Debugging" and enter the puzzle input in the output window.The image contains the exact error I received. The error is related to "string subscript out of range". I would like help in resolving this error.
const int r = 1000;//global variable
const int c = 1000;//global variable
int lights[r][c];//global array
void instruction(string inp)//extracting OFF, ON, or toggle indication from the instruction
{
int* loc;
int coord[4] = { 0 };
char cond = inp[7];
loc = &coord[3];
switch (cond)
{
case 'f':
coordinates(loc, inp);
execute(coord, cond);
break;
case 'n':
coordinates(loc, inp);
execute(coord, cond);
break;
default:
coordinates(loc, inp);
execute(coord, cond);
break;
}
}
void coordinates(int* loc, string inp)//extracting coordinates from the instruction
{
int i, k = 0, l;
l = inp.length()-1;
for (i = l; inp[i] != ','; i--)
{
*loc += (inp[i]-'0') * pow(10,k);
k++;
}
i--;
loc--;
k = 0;
for (; inp[i] != ' '; i--)
{
*loc += (inp[i]-'0') * pow(10,k);
k++;
}
i = i - 9;
loc--;
k = 0;
for (; inp[i] != ','; i--)
{
*loc += (inp[i]-'0') * pow(10,k);
k++;
}
i--;
loc--;
k = 0;
for (; inp[i] != ' '; i--)
{
*loc += (inp[i]-'0') * pow(10,k);
k++;
}
}
void execute(int coord[], char cond)
{
int i, j;
for (i = coord[0]; i <= coord[2]; i++)
{
for (j = coord[1]; j <= coord[3]; j++)
{
if (cond == 'f')
lights[i][j] &= 0;
else if (cond == 'n')
lights[i][j] |= 1;
else
lights[i][j] = ~lights[i][j];
}
}
}
int main()
{
int i, j, k, count = 0;
string inp;
for (i = 0;;i++)
{
cout << "Enter an instruction" << endl;
cin >> inp;
if (inp != "xx")//To manually move to counting the number of lights turned ON
instruction(inp);
else
{
for (j = 0; j < r; j++)
{
for (k = 0; k < c; k++)
{
if (lights[j][k])
count++;
}
}
cout << endl << "Number of lights lit " << count;
break;
}
}
return 0;
}
The problem is most likely this loop (from the coordinates function):
l = inp.length()-1;
for (i = l; inp[i] != ','; i--)
{
*loc += int(inp[i]) * (10 ^ k);
k++;
}
In the very first iteration of the loop then i will be equal to l which is the length of the string, which is out of bounds.
You also don't check if you go out of bounds in the second direction (i becomes negative). You have this problem in all your loops in the coordinates function.
On another note, casting a character to int will not convert a digit character to its corresponding integer value.
Assuming ASCII encoding (the most common encoding available) then the character '2' (for example) will have the integer value 50.
Also the ^ operator it bitwise exclusive OR, not any kind of "power" or "raises" operator. It seems you could need to spend some more times with some of the basics of C++.

Why my program terminate calling the KERNEL32!FileTimeToSystemTime ()?

When I debug, the program collapse in the 3rd line of subset().
There are two picture of running the program and debugging...
#include <iostream>
#include <cmath>
#include <cstdio>
#include <stack>
using namespace std;
int c[6];
char s[101];
int end, yes;
stack<char> sstk;
stack<int> nstk;
int toInt(char ch)
{
int temp;
switch(ch)
{
case 'p': temp = c[0];
break;
case 'q': temp = c[1];
break;
case 'r': temp = c[2];
break;
case 's': temp = c[3];
break;
case 't': temp = c[4];
break;
default:
cout<<"Char incorrect :"<<endl;
}
return temp;
}
int oper(int x, int y, char ch)
{
switch(ch)
{
case 'K':
if(1 == x && 1 == y)
return 1;
else
return 0;
case 'A':
if(0 == x && 0 == y)
return 0;
else
return 1;
case 'C':
if(1 == x && 0 == y)
return 0;
else
return 1;
case 'E':
if(x == y)
return 1;
else
return 0;
default:
cout<<"Operation error"<<endl;
return -1;
}
}
bool isOper(char ch)
{
switch(ch)
{
case 'K': case 'A': case 'N': case 'C': case 'E':
return true;
default:
return false;
}
}
int isTau()
{
char a, b, p, t;
int f; //f==1 means the char was asigned
p = s[0]; cout<<"A time p="<<p<<endl;
if(p == 0)
return -1;
if(!isOper(p) )
return 0;
int i = 1;
while((t=s[i++]) != '!')
{ cout<<t<<endl;
if(isOper(t) ) //If the t char is operator, push previous opertator
{
if(1 == f) //and push the a operand if there is one
nstk.push(a);
sstk.push(p);
p = t; //replace the p with t
f = 0;
continue;
}
int num = toInt(t); //If t is not operatand, trans it to int
if(p == 'N') //To operate either there is an N or f==1(a, b, p)
{
b = (num == 1 ? 0 : 1);
}
if(1 == f)
{
b = oper(a, num, p);
}
else
{
a = num;
f = 1;
continue;
}
while(!sstk.empty() )
{
p = sstk.top();
if('N' == p)
{
b = (b == 1 ? 0 : 1);
sstk.pop();
continue;
}
a = nstk.top();
b = oper(a, b, p);
nstk.pop();
sstk.pop();
}
a = b;
f = 0;
}
if(1 == a)
return 1;
else
return 0;
}
void subset(int n,int *A, int cur)
{
for(int i=0; i<cur; i++)
{ cout<<A[i]<<" ";
c[A[i]] = 1;
} cout<<endl;
if(cur != 0)
{
int t = isTau(); //cout<<"Is Tas: "<<t<<endl;
if(t == -1)
{
end = 1;
return;
}
if(t == 0)
yes = 0;
}
int s = cur ? A[cur-1]+1 : 0;
for(int i=s; i<n; i++)
{
A[cur] = i;
subset(n, A, cur+1);
if(end == 1)
return;
}
}
int main()
{
freopen("input.txt","r",stdin);
do
{ cout<<"Loop : "<<endl;
int i;
char t;
for(i=0; (t=getchar() ) != '\n'; i++)
{
s[i] = t;
}
s[i] = '!';
int *a;
subset(5,a,0); cout<<"what?";
if(yes == 1)
cout<<"tautology"<<endl;
else
cout<<"not"<<endl;
}while(end == 0);
return 0;
}
Running
Call stack
int *a;
subset(5,a,0); cout<<"what?";
Here a is defined as a pointer to integer(s) but is never initialized. Then it is passed to subset which attempts to dereference it...
cout<<A[i]<<" ";
...which results in UB (undefined behavior). Everything that happens from there on, including crashing, is a possible outcome of UB.
You can either point a to an allocated buffer before using it:
int *a = new int[5]; // uninitialized, use instead 'new int[5]();' to initialize to all-0
subset(5,a,0); cout<<"what?";
// ...
// remember to 'delete [] a;' when no longer used
Or you can change a to a local array:
int a[5]; // uninitialized, use instead 'int a[5] = { 0 };` to initialize to all-0
subset(5,a,0); cout<<"what?";

How do I add a character to a string after each iteration of a loop c++

I'm trying to create a roman calculator that reads from a file. I'm struggling to figure out how to add characters to a string. I would like a new character to be added with no spaces after each iteration of a loop this would be used when the program is writing the answer.
I've tried this.
#include <iostream>
#include <iomanip>
#include <string>
#include <fstream>
using namespace std;
string convert_to_Roman(int num)
{
string c;
while (num>0)
{
string c;
if (num >= 1000)
{
num = num - 1000;
return c='M';
}
else if (num >= 500 && num<1000)
{
num = num -500;
return c = 'D';
}
else if (num >= 100 && num<500)
{
num = num -100;
return c= 'C';
}
else if (num >= 50 && num<100)
{
num = num - 50;
return c = 'L';
}
else if (num >= 10 && num<50)
{
num = num - 10;
return c = 'X';
}
else if (num >= 5 && num<10)
{
num = num - 5;
return c = 'V';
}
else if (num<5)
{
num = num - 1;
return c = 'I';
}
c +=c;
//cout<<"answer= "<< + answer<<endl;
}
cout << c;
}
int convert_from_Roman(string & s)
{
int num=0;
int length; //length of string
length = s.length();
for (int i = 0; i < length; i++)
{
char c = s[i];
int digit;
if (c == 'M')
{
return num = 1000;
}
else if (c == 'D')
{
return num = 500;
}
else if (c == 'C')
{
return num = 100;
}
else if (c == 'L')
{
return num = 50;
}
else if (c == 'X')
{
return num = 10;
}
else if (c == 'V')
{
return num = 5;
}
else if (c == 'I')
{
return num = 1;
}
else
{
cout << "invalid entry" << endl;
continue;
}
num += num;
}
cout<<num<<endl;
}
void print_Result(/* figure out the calling sequence */)
{
// fill in your code
}
// Note the call by reference parameters:
string finalAnswer()
{
string operand1, operand2;
char oper;
cout << "enter operation: " << endl;
cin >> operand1 >> operand2 >> oper;
int value1, value2, answer;
value1 = convert_from_Roman(operand1);
value2 = convert_from_Roman(operand2);
switch (oper)
{
case '+':
{
answer = value1 + value2;
break;
}
case '-':
{
answer = value1 - value2;
break;
}
case '*':
{
answer = value1*value2;
break;
}
case '/':
{
answer = value1 / value2;
break;
}
default:
{
cout << "bad operator : " << oper << endl;
return;
}
string answerInRoman = convert_to_Roman(answer);
return answerInRoman;
cout << "answer= " << answerInRoman << " (" << answer << ") " << endl;
}
You can simply use concatenation like so.
char addThis;
string toThis;
addThis = 'I';
toThis = "V";
toThis += addThis;
or
toThis = toThis + addThis;
If you want to place the number somewhere other than the end of a string, you can access the elements of a string like an array toThis[0] is equal to 'V'.
If you are not using std::string as mentioned below, this can be done with a dynamic character array and an insert method that resizes the array properly as follows:
#include <iostream>
using namespace std;
void addCharToArray(char * & array, int physicalSize, int & logicalSize, char addThis)
{
char * tempPtr;
if (physicalSize == logicalSize)
{
tempPtr = new char[logicalSize + physicalSize];
for (int i = 0; i < logicalSize; i++)
{
tempPtr[i] = array[i];
}
delete [] array;
array = tempPtr;
}
array[logicalSize] = addThis;
logicalSize++;
}
int main()
{
char addThis = 'I';
char * toThis;
int physicalSize = 1;
int logicalSize = 0;
toThis = new char[physicalSize];
toThis[0] = 'V';
logicalSize++;
//when adding into the array, you must perform a check to see if you must add memory
addCharToArray(toThis, physicalSize, logicalSize, addThis);
for (int i = 0; i < logicalSize; i++)
{
cout << toThis[i];
}
cout << endl;
return 0;
}