I'm trying to go through a vector of strings with an iterator, but it needs to check a few values in advance. I tried doing this with the following code:
typedef std::vector<std::string>::iterator Cursor;
std::string check(Cursor& at) {
int number;
std::string ans = *at;
if (ans.empty()) {
return "NOT OK";
} else {
std::stringstream ss(ans);
ss >> number >> ans;
if (ans == "NOT OK") {
return "NOT OK";
} else if (ans == "VALUE") {
int x;
ss >> x;
std::string result("OK");
for (Cursor c = at; x > 0; ++c, --x) {
result = check(c);
}
return result;
} else {
return "OK";
}
}
}
But this code crashes when it enters the for-loop and I have no idea why.
int x;
ss >> x; // Here you should check whether x has the expected value.
std::string result("OK");
for (Cursor c = at; x > 0; ++c, --x) { // here you do not check whether c is within boundaries.
result = check(c);
}
// c should start from at+1, otherwise it may result in infinite recursion.
// Also, termination condition should be added.
for (Cursor c = at+1; x > 0 && c != myVec.end(); ++c, --x) {
Related
I am trying previous year's codejam question of round 1A
link to question
i have submitted this code(start reading from main method, for ease)-
#include <bits/stdc++.h>
using namespace std;
#define range(t) for (int i = 0; i < t; i++)
#define rangeG(i, t) for (i = 0; i < t; i++)
#define printVec(vec) \
for (auto c : vec) \
{ \
cout << c << endl; \
}
vector<string> separate(string s)
{
vector<string> result;
range(s.size())
{
if (s[i] == '*')
{
string temp = s.substr(0, i + 1);
if (temp.size() > 1)
{
result.push_back(temp);
}
s = s.substr(i, s.size());
i = 0;
}
else if (i == (s.size() - 1))
{
string temp = s.substr(0, i + 1);
result.push_back(temp);
s = s.substr(i, s.size());
}
}
return result;
}
void removeAsterisk(string &s)
{
s.erase(remove(s.begin(), s.end(), '*'), s.end());
}
bool setStart(string s, string &start)
{
bool possible = 1;
removeAsterisk(s);
range(min(s.size(), start.size()))
{
if (s[i] != start[i])
{
possible = 0;
}
}
if (possible)
{
if (s.size() >= start.size())
{
start = s;
}
}
return possible;
}
bool setEnd(string s, string &end)
{
bool possible = 1;
removeAsterisk(s);
range(min(s.size(), end.size()))
{
if (s[s.size() - 1 - i] != end[end.size() - 1 - i])
{
possible = 0;
}
}
if (possible)
{
if (s.size() >= end.size())
{
end = s;
}
}
return possible;
}
void solve()
{
int n;
cin >> n;
vector<string> allS;
bool possible = 1;
string start = "";
string end = "";
string middle = "";
string result = "";
while (n--)
{
string str;
cin >> str;
if (count(str.begin(), str.end(), '*') == 0)
{
result = str;
}
vector<string> temp = separate(str);
for (string s : temp)
{
if (s[0] != '*')
{
possible = setStart(s, start);
}
if (s[s.size() - 1] != '*')
{
possible = setEnd(s, end);
}
if (possible && count(s.begin(), s.end(), '*') == 0)
{
result = s;
break;
}
if (s[0] == '*' && s[s.size() - 1] == '*')
{
removeAsterisk(s);
middle += s;
}
}
}
if (possible)
{
if (result.size() == 0)
{
result = start + middle + end;
}
cout << result << "\n";
}
else
{
cout << "*\n";
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t = 0;
cin >> t;
range(t)
{
cout << "Case #" << i + 1 << ": ";
solve();
}
return 0;
}
it seems correct to me and i have tested many times for many examples, but it is losing in test set-1(exactly one * (asterisk) character and and always the first character of string). Can anyone tell what's wrong?
you can consider code of first ranked here (it has all solutions,check only for "pattern matching" task) for help. I know that the wrong answer is an edge case and if it passes test set 1 then it will pass others.
I am just kind of starting to code and this was in a book that I am using to learn C++. It should be working straight from the book and I can't figure out how to fix it.
I think the problem might be because it lacks the constant operator but if you add it in doesn't that prevent you from modifying the value?
The book is by Drozdek titles Data Structures and Algorithms in C++ if you need that. Thanks for the help!
#include <iostream>
#include <cctype>
#include <cstdlib>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
class Variable {
public:
char id;
int exp;
Variable() { // required by <vector>;
}
Variable(char c, int i) {
id = c; exp = i;
}
bool operator== (const Variable& v) const {
return id == v.id && exp == v.exp;
}
bool operator< (const Variable& v) const { // used by sort();
return id < v.id;
}
};
class Term {
public:
Term() {
coeff = 0;
}
int coeff;
vector<Variable> vars;
bool operator== (const Term&) const;
bool operator!= (const Term& term) const { // required by <list>
return !(*this == term);
}
bool operator< (const Term&) const;
bool operator> (const Term& term) const { // required by <list>
return *this != term && (*this < term);
}
int min(int n, int m) const {
return (n < m) ? n : m;
}
};
class Polynomial {
public:
Polynomial() {
}
Polynomial operator+ (Polynomial&);
void error(char *s) {
cerr << s << endl; exit(1);
}
private:
list<Term> terms;
friend istream& operator>> (istream& in, Polynomial& polyn) {
char ch, sign, coeffUsed, id;
int exp;
Term term;
in >> ch;
while (true) {
coeffUsed = 0;
if (!isalnum(ch) && ch != ';' && ch != '-' && ch != '+')
polyn.error("Wrong character entered2");
sign = 1;
while (ch == '-' || ch == '+') { // first get sign(s) of Term
if (ch == '-')
sign *= -1;
ch = in.get();
if (isspace(ch))
in >> ch;
}
if (isdigit(ch)) { // and then its coefficient;
in.putback(ch);
in >> term.coeff;
ch = in.get();
term.coeff *= sign;
coeffUsed = 1;
}
else term.coeff = sign;
int i;
for (int i = 0; isalnum(ch); i++) { // process this term:
id = ch; // get a variable name
ch = in.get();
if (isdigit(ch)) { // and an exponent (if any);
in.putback(ch);
in >> exp >> ch;
}
else exp = 1;
term.vars.push_back(Variable(id,exp));
}
polyn.terms.push_back(term); // and include it in the linked list;
term.vars.resize(0);
if (isspace(ch))
in >> ch;
if (ch == ';') // finish if a semicolon is entered;
if (coeffUsed || i > 0)
break;
else polyn.error("Term is missing"); // e.g., 2x - ; or just ';'
else if (ch != '-' && ch != '+') // e.g., 2x 4y;
polyn.error("wrong character entered");
}
for (list<Term>::iterator it = polyn.terms.begin(); it != polyn.terms.end(); it++)
if (it->vars.size() > 1)
sort(it->vars.begin(),it->vars.end());
return in;
}
friend ostream& operator<< (ostream& out, const Polynomial& polyn) {
int afterFirstTerm = 0, i;
for (list<Term>::const_iterator pol = polyn.terms.begin(); pol != polyn.terms.end(); pol++) {
out.put(' ');
if (pol->coeff < 0) // put '-' before polynomial
out.put('-'); // and between terms (if needed);
else if (afterFirstTerm) // don't put '+' in front of
out.put('+'); // polynomial;
afterFirstTerm++;
if (abs(pol->coeff) != 1) // print a coefficient
out << ' ' << abs(pol->coeff);// if it is not 1 nor -1, or
else if (pol->vars.size() == 0) // the term has only a coefficient
out << " 1";
else out.put(' ');
for (i = 1; i <= pol->vars.size(); i++) {
out << pol->vars[i-1].id; // print a variable name
if (pol->vars[i-1].exp != 1) // and an exponent, only
out << pol->vars[i-1].exp; // if it is not 1;
}
}
out << endl;
return out;
}
};
// two terms are equal if all varibles are the same and
// corresponding variables are raised to the same powers;
// the first cell of the node containing a term is excluded
// from comparison, since it stores coefficient of the term;
bool Term::operator== (const Term& term) const {
int i;
for (i = 0; i < min(vars.size(),term.vars.size()) &&
vars[i] == term.vars[i]; i++);
return i == vars.size() && vars.size() == term.vars.size();
}
bool Term::operator< (const Term& term2) const { // used by sort();
if (vars.size() == 0)
return false; // *this is just a coefficient;
else if (term2.vars.size() == 0)
return true; // term2 is just a coefficient;
for (int i = 0; i < min(vars.size(),term2.vars.size()); i++)
if (vars[i].id < term2.vars[i].id)
return true; // *this precedes term2;
else if (term2.vars[i].id < vars[i].id)
return false; // term2 precedes *this;
else if (vars[i].exp < term2.vars[i].exp)
return true; // *this precedes term2;
else if (term2.vars[i].exp < vars[i].exp)
return false; // term2 precedes *this;
return ((int)vars.size() - (int)term2.vars.size() < 0) ? true : false;
}
Polynomial Polynomial::operator+ (Polynomial& polyn2) {
Polynomial result;
list<Term>::iterator p1, p2;
bool erased;
for (p1 = terms.begin(); p1 != terms.end(); p1++) // create a new polyn
result.terms.push_back(*p1); // from copies of *this
for (p1 = polyn2.terms.begin(); p1 != polyn2.terms.end(); p1++) // and
result.terms.push_back(*p1); // polyn2;
for (p1 = result.terms.begin(); p1 != result.terms.end(); ) {
for (p2 = p1, p2++, erased = false; p2 != result.terms.end(); p2++)
if (*p1 == *p2) { // if two terms are equal (except
p1->coeff += p2->coeff; // for the coefficient), add the
result.terms.erase(p2); // two coefficients and erase
if (p1->coeff == 0) // a redundant term; if the
result.terms.erase(p1);// coefficient in retained term
erased = true; // is zero, erase the term as well;
break;
}
if (erased) // restart processing from the beginning
p1 = result.terms.begin(); // if any node was erased;
else p1++;
}
result.terms.sort();
return result;
}
int main() {
Polynomial polyn1, polyn2;
cout << "Enter two polynomials, each ended with a semicolon:\n";
cin >> polyn1 >> polyn2;
cout << "The result is:\n" << polyn1 + polyn2;
return 0;
}
On line 52, the error function should take a const char*, rather than a char*:
void error(char* s) { // WRONG
void error(const char *s) { // RIGHT
cerr << s << endl; exit(1);
}
This is because strings like "Hello" are arrays of const char, because you can't modify literals. If you make this change, the code should work. The compiler won't convert pointers to const types to regular pointers, because that would break the constness.
Also, on line 82 ad 83, the textbook writes:
int i; // Error: i never initialized
for (int i = 0; isalnum(ch); i++) { // process this term:
It looks like it was trying to use i both inside and outside the for loop, but the author accidentally declared i a second time at the start of the loop. We can fix it by doing this:
int i = 0; // This is probably what was intended
for(; isalnum(ch); i++) { // process this term:
Why can't I modify string literals?
Imagine if you could do
5 = 10; // This is complete and utter nonsense.
This doesn't make any sense! You can't assign 5 to 10. In the same way, this is also nonsense:
"hello" = "blarg"; // This is also nonsense
"hello" is always "hello", and never anything else. If the compiler allowed you to write
"hello"[0] = 'H'; // This is also nonsense
This would be modifying "hello", which could just... break your program. It's wrong; it's evil. In fact, the string literal "hello" might even be placed in a section of memory that's flagged as const by the Operating System itself.
Why does the compiler give you the error (or warning)
If you have char*, that is a pointer to a char. If you have const char*, that is a pointer to a const char. If you could go from const char* to char*, this would allow you to modify const memory, which could break the program:
// If you could do this, you could modify "hello"
// Modifying "hello" is nonsense, so this should be nonsense too:
char* s = "hello";
s[0] = 'H'; // How you'd modify "hello"
As a result, string literals can only be assigned to const char*:
// Because s contains const chars, elements of s can't be modified so this is fine
const char* s = "hello"; // This is OK
Why did the textbook contain the error?
The language used to let people do really unsafe stuff, like modifying string literals. This is extremely bad practice and it breaks optimizations the compiler uses to make programs smaller and faster.
The textbook is probably written by someone who's used to writing old, unsafe code.
I tried to write a calulator which allows for chaining.
So my firstSet() function handles division an multiplication and the. modifies the vector, until the secondSet() function handle addition and subtraction.I had some bugs with the part where I am erasing vector elements, which is where I suspect the segmentation fault is occurring from.
#include <vector>
#include <iostream>
//Structure:
//Vector 'stream' of data objects , where each element is either a num or operator
//Heirarchy:
//1.* & /
//2.+ & -
//expected input : Spaced integers with operators and a semicolon to end the input statement.
//for ex:
//3+2;
//5/6;
struct Data
{
char type;
int val;
char op;
Data(char x , char y)
: type(x) , op(y){}
Data(char x , int y) : type(x) , val(y){}
};
void firstSet(std::vector<Data> & v) // / & *
{
int temp;
for (auto i = v.begin(); i != v.end()-1 ; ++i)
{
if ((*i).type == 'o' && ((*i).op == '/' || (*i).op == '*'))
{
if ((*i).op == '/')
{
temp = (*(i-1)).val / (*(i+1)).val;
}
if ((*i).op == '*')
{
temp = (*(i-1)).val * (*(i+1)).val;
}
(*(i-1)).val = temp; // change lhs
v.erase(i); //delete operator
v.erase(i); //delete rhs
}
}
}
void secondSet(std::vector<Data> & v) // + & -
{
int temp;
for (auto i = v.begin(); i != v.end() ; ++i)
{
if ((*i).type == 'o' && ((*i).op == '+' || (*i).op == '-') )
{
if ((*i).op == '+')
{
temp = (*(i-1)).val + (*(i+1)).val;
}
if ((*i).op == '-')
{
temp = (*(i-1)).val - (*(i+1)).val;
}
(*(i-1)).val = temp;
v.erase(i);
v.erase(i);
}
}
}
int main()
{
std::vector<Data> v;
char T;
std::cin >>T;
while (T != ';')
{
if (T == '/' || T == '*' || T == '+' || T == '-')
{
v.push_back(Data{'o' , T});
}
if (T >= '0' && T <= '9')
{
std::cin.putback(T);
int x;
std::cin >> x;
v.push_back(Data{'n' , x});
}
std::cin >> T;
}
firstSet(v);
secondSet(v);
std::cout << v[0].val;
}
p.s any comments on code readability and neatness in general would be helpful as I want the code to be 'clean'.
Using i after v.erase(i) is invalid, because calling erase [...]invalidates iterators and references at or after the point of the erase, including the end() iterator.[...]
So the second v.erase(i) is wrong, but also continuing the loop using ++i is invalid, and would result in undefined behavior.
You need to replace i with a valid iterator after your erase called. E.g. using:
i = v.erase(i);
But doing so will result in skipping each element after the erased one, so you need to change the logic of your loop.
But there are other parts that are invalid:
(*(i-1)).val = temp; will be invalid if i==v.begin()
(*(i+1)).val will be invalid if (i+1)==v.end()
So you need to think over the complete logic of your code in general.
I'm using the behavior of std::cin leaving the extraneous input inside the buffer until they are called again. Could that be a bad practice?
Example code -
double getDoubleInput()
{
double x{};
std::cin >> x;
assert("Syntax Error!!" && !std::cin.fail());
return x;
}
char getOperatorInput()
{
char x{};
std::cin >> x;
bool b{x == '+' || x == '-' || x == '*' || x == '/' || x == '^'};
assert("Syntax Error!!" && b);
return x;
}
double calculate(int x)
{
char op{getOperatorInput()};
double tmp{getDoubleInput()};
if(op == '+')
{
return x + tmp;
}
else if(op == '-')
{
return x - tmp;
}
else if(op == '*')
{
return x * tmp;
}
else if(op == '/')
{
return x / tmp;
}
return 0;
}
void calculator()
{
std::cout << "Enter your expression : ";
double result{};
int loopCount{0};
do{
if(loopCount == 0)
result = getDoubleInput();
result = calculate(result);
loopCount++;
}
while(std::cin.peek() != '\n'); //LIKE THIS
std::cout << "Your result is : " << result << '\n';
}
So I am working on some homework for my uni and need to convert a string to a float. For whatever reason g++ is complaining that the 'stof' function doesn't exist. Although I have included the required header. Here is my code, the error is on the line that says
holder = stof(x.substr(0, end_of_num));
#include <iostream>
#include <string>
#include <list>
using namespace std;
float process_func(string x);
bool isPartOfNum(char x);
int main() {
string x;
while (true) {
cout << "input a string" << endl;
getline(cin, x);
cout << process_func(x);
}
return 0;
}
float process_func(string x) {
int end_of_num =0;// used to find last index from num
int negMult = 1; //used to multiply value at end if there was a negative
bool onNum = false; //used to
list <float> numList;
list <char> operList;
if ((x.at(0) < 48 || x.at(0) > 57) && x.at(0) != '-') //check if start of string doesnt have a number or negative symbol
return -1;
if (x.at(0) != '-')
negMult = -1;
float holder;// temp holder for floats
int i = 0;
while (i<x.length()) {
if (isPartOfNum(x.at(i))) {
end_of_num++;
onNum = true;
}
else if (onNum) {
holder = stof(x.substr(0, end_of_num));
numList.push_back(holder); //adds num as float to list
x.erase(0, end_of_num + 1); //+1 removes the space after the number before the operator
end_of_num = 0;
onNum = false;
}
if (x.at(i) == '+' || x.at(i) == '-' || x.at(i) == '*' || x.at(i) == '/') {
operList.push_back(x.at(i));
}
} //at this point both lists should be full of all needed pieces of info
int answer = 0;
int temp;
bool firstOper=true; // used to hold first operation
while (numList.size() >=2) { //requires at least 2 entries for last operation
while (!operList.empty()) {
temp = numList.front();
numList.pop_front();
if (operList.front() == '+') {
if (firstOper) {
answer = temp + numList.front();
numList.pop_front();
firstOper = false;
}
else {
answer += temp;
}
}
else if (operList.front() == '-') {
if (firstOper) {
answer = temp - numList.front();
numList.pop_front();
firstOper = false;
}
else {
answer -= temp;
}
}
else if (operList.front() == '*') {
if (firstOper) {
answer = temp * numList.front();
numList.pop_front();
firstOper = false;
}
else {
answer *= temp;
}
}
else if (operList.front() == '/') {
if (firstOper) {
answer = temp / numList.front();
numList.pop_front();
firstOper = false;
}
else {
answer /= temp;
}
}
operList.pop_front();
}
}
return answer;
}
bool isPartOfNum(char x) {
if ((x >= 48 && x <= 57) || (x == '-' || x == '.'))
return true;
return false;
}
Solved by compiling using c++ 11