Reputation: 11
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;
}
Upvotes: 0
Views: 86
Reputation: 10740
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 const
ness.
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:
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.
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
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.
Upvotes: 2