I have this code which is about polynomials multiplication.
I meet no error, just what I want is to sort the terms based on degrees (from lower degree to higher).
If I add condition in operator* in //commented part, it will be printed too many of times. I would like to know if I can use m_Polynomial.sort()? If yes how? If not, what other methods can I use?
As it is both for printing polynomials and their multiplication result it would be nice if it could be added in print function.
Also if it is possible to change the printing style of Polynomials to desired format (to add coefficients of same degree terms)
Minimal code:
#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include <vector>
using namespace std;
typedef struct Node
{
double cof; // coefficient
int deg; // degree
} Node;
class CPolynomial
{
public:
CPolynomial();
CPolynomial(const string& file);
~CPolynomial();
CPolynomial operator*(const CPolynomial &right);
CPolynomial& operator=(const CPolynomial &right);
void Print() const;
private:
void ReadFromFile(string file);
private:
list<Node> m_Polynomial;
};
int main()
{
CPolynomial p1("P3.txt");
CPolynomial p2("P4.txt");
CPolynomial p3;
p1.Print();
p2.Print();
p3 = p1*p2;
p3.Print();
system("pause");
return 0;
}
CPolynomial::CPolynomial()
{
Node term;
term.cof = 0;
term.deg = 0;
m_Polynomial.push_back(term);
}
CPolynomial::~CPolynomial()
{
m_Polynomial.clear();
}
CPolynomial::CPolynomial(const string& file)
{
ReadFromFile(file);
}
CPolynomial CPolynomial:: operator*(const CPolynomial &right)
{
CPolynomial result;
result.m_Polynomial = m_Polynomial;
for (list<Node>::iterator itr = result.m_Polynomial.begin(); itr != result.m_Polynomial.end(); ++itr)
{
itr->cof = 0;
itr->deg = 0;
}
Node term;
Node termR;
Node temp;
for (list<Node>::const_iterator it = m_Polynomial.begin(); it != m_Polynomial.end(); ++it)
{
for (list<Node>::const_iterator itR = right.m_Polynomial.begin(); itR != right.m_Polynomial.end(); ++itR)
{
term = *it;
termR = *itR;
temp.cof = termR.cof* term.cof;
temp.deg = termR.deg + term.deg;
for (list<Node>::iterator itr = result.m_Polynomial.begin(); itr != result.m_Polynomial.end(); ++itr)
{
if (temp.deg == itr->deg)
{
temp.cof += itr->cof;
itr->cof = 0;
}
// if(temp.deg < it->deg)
//result.m_Polynomial.insert(it, temp);
}
result.m_Polynomial.push_back(temp);
}
}
return result;
}
CPolynomial& CPolynomial:: operator=(const CPolynomial &right)
{
this->m_Polynomial = right.m_Polynomial;
return *this;
}
void CPolynomial::Print() const
{
list<Node>::const_iterator it;
for (it = m_Polynomial.begin(); it != m_Polynomial.end(); it++)
{
if (it->cof == 0)
{
;
}
else
{
if (it->cof > 0)
{
if (it != m_Polynomial.begin()) // if 'it' is not the first term, '+' is not necessary
cout << "+";
}
cout << it->cof;
if (it->deg != 0)
cout << "x^" << it->deg;
}
}
cout << endl;
}
void CPolynomial::ReadFromFile(string file)
{
Node term;
fstream MyFile;
string p;
int num;
MyFile.open(file);
if (!MyFile.is_open())
{
cerr << "Unable to open input file" << endl;
exit(EXIT_FAILURE);
}
else
{
MyFile >> p >> num;
std::list<Node>::iterator it = m_Polynomial.begin();
for (int i = 0; i < num; i++)
{
MyFile >> term.deg >> term.cof;
m_Polynomial.push_back(term);
}
MyFile.close();
}
}
P1.txt
P 8
0 2
5 -3
12 5
2 6
5 7
3 -4
2 9
2 2
P4.txt
P 2
1 4
4 -3
Output
2-3^5+5x^12+6x^2+7x^5-4x^3+9x^2+2x^2 (P1)
4x^1-3x^4 (P2)
8x^1+20x^13-15x^16_12x^9-22x^4+12x^7+68x^3 (P1*P2)
desired output:
2+17x^2-4x^3+4x^5+5x^12
4x^1-3x^4
8x^1+68x^3-22x^4+12x^7_12x^9+20x^13-15x^16
Your operator modifies its left operand, why?
If you say p3 = p1 * p2; then it is wrong to modify p1, you should return a new object with a new value, and not alter the operands.
One solution is to provide operator*= as a member function that alters its left operand, then define operator* as a non-member function:
CPolynomial operator*(const CPolynomial& lhs, const CPolynomial& rhs)
{
CPolynomial result = lhs;
result *= rhs;
return result;
}
The bug appears to be in AddOneTerm where you do the comparisons wrong. Your loop will insert the new term at the first position where (term.deg >= it->deg) but it should be the last position where that is true.
Also you should use AddOneTerm(term) instead of m_Polynomial.push_back(term) in ReadFromFile to ensure the terms are kept in the correct order.
You also have very confusing use of iterators:
std::list<Node>::iterator next_it;
next_it = ++it;
Now both next_it and it have been incremented, so they are both the next term. Why?
I suggest something much simpler:
void CPolynomial::AddOneTerm(Node term)
{
auto it = m_Polynomial.begin();
while (it != m_Polynomial.end() && it->deg < term.deg)
{
++it;
}
if (it != m_Polynomial.end() && term.deg == it->deg)
{
it->cof += term.cof;
}
else
{
m_Polynomial.insert(it, term);
}
}
You could also define a comparison operator for Node objects:
bool operator<(const Node& l, const Node& r)
{
return l.deg < r.deg;
}
Now you can easily sort your list<Node> structure, and you can use lower_bound to find the right position in AddOneTerm:
void CPolynomial::AddOneTerm(Node term)
{
auto it = std::lower_bound(m_Polynomial.begin(), m_Polynomial.end(), term);
if (it != m_Polynomial.end() && term.deg == it->deg)
{
it->cof += term.cof;
}
else
{
m_Polynomial.insert(it, term);
}
}
Related
I am defining my own string class called StringSet using a vector of strings. I am assigned to overload the >>, <<, ==, >, >=, +, += and * operators, and ran into a problem with <<. The output should be:
Welcome to stringset
hi everyone
"all" does not exist in the set.
hi
But it seems to be skipping the second and third lines. I am very new to overloading operators, so I am probably overlooking an obvious mistake.
header and class declaration:
#include <iostream>
#include <vector>
#include<string>
#include <iterator>
#include <algorithm>
#include <fstream>
using namespace std;
class StringSet
{
public:
//Constructor
StringSet();
//Copy Constructor
StringSet(const StringSet& s);
//Default constructors
StringSet(string initialStrings[], const int ARRAYSIZE);
//Destructor
~StringSet();
void add(const string s);
void remove(const string s);
//Returns length
int size()
{
return length;
}
// Overload the << operator so that it outputs the strings
friend ostream& operator <<(ostream& outs, const StringSet& s);
private:
//size of the vector
int length;
// Vector to store strings
vector <string> data;
};
function definitions:
ostream& operator<<(ostream& outs, const StringSet& s)
{
outs << "\n";
for (int i = 0; i < s.length; i++)
{
outs << s.data[i] << " ";
}
outs << "\n";
return outs;
}
//Add a string to the vector
void StringSet::add(const string s)
{
bool c = check(s);
if (c == false)
{
data.push_back(s);
}
else
{
cout << "\"" << s << "\" already exists in the set.";
}
}
// Remove a string from the vector
void StringSet::remove(const string s)
{
bool c = check(s);
if (c == true)
{
vector<string>::iterator position = search(s);
data.erase(position);
}
else
{
cout << "\"" << s << "\" does not exist in the set\n";
}
}
StringSet::StringSet()
{
length = 0;
}
StringSet::StringSet(string initialStrings[], const int ARRAYSIZE)
{
for (int i = 0; i < data.size(); i++)
{
initialStrings[i] = " ";
}
}
// Copy constructor
StringSet::StringSet(const StringSet& s)
{
for (int i = 0; i < data.size(); i++)
{
data[i] = s.data[i];
}
}
StringSet::StringSet()
{
length = 0;
}
StringSet::StringSet(string initialStrings[], const int ARRAYSIZE)
{
for (int i = 0; i < data.size(); i++)
{
initialStrings[i] = " ";
}
}
// Copy constructor
StringSet::StringSet(const StringSet& s)
{
for (int i = 0; i < data.size(); i++)
{
data[i] = s.data[i];
}
}
// Check if a string exists in the vector
bool StringSet::check(const string s)
{
vector<string>::iterator it = find(data.begin(), data.end(), s);
if (it != data.end())
{
return true;
}
else
{
return false;
}
}
Main function:
int main()
{
ofstream outs;
ifstream ins;
StringSet doc1, doc2, query
cout << "Welcome to stringset\n";
doc1.add("hi");
doc1.add("everyone");
outs << doc1;
doc1.remove("everyone");
doc1.remove("all");
outs << doc1;
}
If you use a variable that stores the size of the set, you should increment/decrement it when adding/removing elements. You can also change the definition of the StringSet::size():
int size() const
{
return static_cast<int>(data.size());
}
I am required to implement a dynamic array that adjusts, dynamically, in accordance with the number of value (temperatures) that are input into the code. I have written the majority of the code for this to be possible, however I have run into a bug and for the life of me, have been unable to locate the issue.
The program is supposed to output the values of temp_a, make temp_b = temp_a, output the value of temp_b, and then clear the value of temp_a, and finally output the values of temp_b once more.
However, when I compile the program, it outputs that the list is full and cannot add any more values, meaning there is a logic error somewhere in the code.
Please forgive me for the lengthy code, as soon as I can locate the error, the code shall be separated into multiple compilations.
#include <iostream>
using namespace std;
class TemperatureList {
private:
int* temp; // pointer to dynamic array
short current_size; // current number of elements
short max_size; // max number of elements allowed in this list
public:
// Overloading assignment operator
void operator =(const TemperatureList& another_list);
// === Constructors ===
// Default constructor
TemperatureList();
// Constructor that accepts an integer parameter that specifies the max length of the list
TemperatureList(int max);
// Copy constructor that accepts another List as parameter
TemperatureList(const TemperatureList& another_list);
// Destructor
~TemperatureList();
// === Modifier functions ===
// add new_value to end of list if there is still space
void add_temperature(int new_value);
// === Accessor functions ===
// return current current_size of the list
short get_current_size();
// === Other functions ===
// return the last element, or 0 if the list is empty, with a warning output
int get_last();
// return element at the position-th position, or 0 if the list is empty, with a warning output
int get_temp(short position);
// returns if current_size == 0
bool set_temp(short position, int value);
// returns if current_size == 0
bool empty();
// returns if current_size == max_size
bool full();
// Output list separated by commas
friend ostream& operator <<(ostream& outs, const TemperatureList& list);
};
int main() {
TemperatureList temp_a;
temp_a.add_temperature(23.5);
temp_a.add_temperature(24.6);
cout << temp_a;
TemperatureList temp_b = temp_a;
cout << temp_b;
temp_a = TemperatureList();
cout << "Now there's no temperatures in a.\n";
cout << temp_a;
cout << "How about temperatures in b?\n";
cout << temp_b;
return 0;
}
void TemperatureList::operator =(const TemperatureList& another_list) {
delete[] temp;
current_size = another_list.current_size;
max_size = another_list.max_size;
if (current_size > 0) {
temp = new int[max_size];
for (int i = 0; i < max_size; i++) {
temp[i] = another_list.temp[i];
}
}
else {
temp = NULL;
}
}
TemperatureList::TemperatureList() {
current_size = 0;
max_size = 0;
temp = NULL;
}
TemperatureList::TemperatureList(int max) : max_size(max) {
current_size = 0;
temp = new int[max];
}
TemperatureList::TemperatureList(const TemperatureList& another_list) {
current_size = another_list.current_size;
max_size = another_list.max_size;
if (current_size > 0) {
temp = new int[max_size];
for (int i = 0; i < max_size; i++) {
temp[i] = another_list.temp[i];
}
}
else {
temp = NULL;
}
}
TemperatureList::~TemperatureList() {
//cout << "== I am in destructor ==\n";
delete[] temp;
}
void TemperatureList::add_temperature(int new_value) {
if (current_size < max_size) {
temp[current_size] = new_value;
current_size++;
}
else {
cout << "Cannot add value to the list. It is full.\n";
}
}
int TemperatureList::get_last() {
if (empty()) {
cout << "The list is empty\n";
return 0;
}
else {
return temp[current_size - 1];
}
}
int TemperatureList::get_temp(short position) {
if (current_size >= position) {
return temp[position - 1];
}
else {
cout << "There is no temperature\n";
return 0;
}
}
bool TemperatureList::set_temp(short position, int value) {
if (current_size >= position) {
temp[position - 1] = value;
return true;
}
else {
return false;
}
}
short TemperatureList::get_current_size() {
return current_size;
}
bool TemperatureList::empty() {
return (current_size == 0);
}
bool TemperatureList::full() {
return (current_size == max_size);
}
ostream& operator <<(ostream& outs, const TemperatureList& list) {
int i;
for (i = 0; i < (list.current_size - 1); i++) {
outs << list.temp[i] << ",";
}
outs << list.temp[i];
return outs;
}
The logic error seems to stem from the fact that you initialize your current_size and max_size to zero. So, unless your run the overloaded constructor (wherein you’re set the max_size), every call to addTemperature() is going to fail the (current_size < max_size) check because they are both equal to zero.
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.
String is my own string class and Stack is my own stack class.
I am trying to change infix to postfix with values that are separated by spaces.
The function below pretty much works but also returns a "Segmentation fault (core dumped)".
String postfix(String infix){
std::vector<String> vec;
vec = infix.split(' ');
Stack<String> tmp;
String right, left, op;
int i = 0;
while (vec[i] != ';'){
if (vec[i] == ')'){
right = tmp.pop();
op = tmp.pop();
left = tmp.pop();
tmp.push(left + ' ' + right + ' ' + op);
}else{
if (vec[i] != '(' && vec[i] != ' ')
tmp.push(vec[i]);
}
++i;
}
String postfix = tmp.pop();
return postfix;
}
I do not understand why this is. Any help would be appreciated.
#ifndef STACK_HPP
#define STACK_HPP
template <typename T>
class Node{
public:
T data;
Node<T>* next;
Node() { data().next(0); } ;
Node (const T& x) : data (x), next(0) {};
};
template <typename T>
class Stack{
public:
Stack() : tos(0){};
~Stack();
Stack(const Stack<T>&);
void swap(Stack<T>& rhs);
Stack<T>& operator= (Stack<T> rhs) { swap(rhs); return *this; };
bool isEmpty() const { return tos == 0; };
T pop();
void push(const T&);
private:
Node<T> *tos;
};
///////////////////////////////////////////////////////////////
template <typename T>
Stack<T>::~Stack(){
while(tos != 0){
Node<T> *tmp = tos;
tos = tos -> next;
delete tmp;
}
}
template <typename T>
void Stack<T>::swap(Stack<T>& rhs){
Node<T> *tmp = tos;
tos = rhs.tos;
rhs.tos = tmp;
}
template <typename T>
Stack<T>::Stack(const Stack<T>& actual){
Node<T> *tmp = actual.tos, *bottom = 0;
tos = 0;
while (tmp != 0){
if(tos == 0){
tos = new Node<T>(tmp -> data);
bottom = tos;
}else{
bottom -> next = new Node<T>(tmp -> data);
bottom = bottom -> next;
}
tmp = tmp -> next;
}
}
template<typename T>
T Stack<T>::pop(){
T result = tos -> data;
Node<T> *tmp = tos;
tos = tos -> next;
delete tmp;
return result;
}
template <typename T>
void Stack<T>::push(const T& x){
Node<T> *tmp = new Node<T> (x);
tmp -> next = tos;
tos = tmp;
}
#endif
//bruce pucci
//string
//cs23001
#include <iostream>
#include <cassert>
#include <vector>
#include <fstream>
#include "string.hpp"
///////////////////////////////string class friend functions////////////////////////
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////I/O/////////////////////////////////////////////
std::ostream& operator<<(std::ostream& out, const String& print){//std::cout operator
int i = 0;
while (print.arr[i] > 0){
out << print.arr[i];
++i;
}
return out;
}
std::ifstream& operator>>(std::ifstream& in, String& rhs){//ifstream operator.
char tmp[stringSize];//grabs word by word (chars serperated by whitespace).
in >> tmp;
rhs = String(tmp);
return in;
}
////////////////////////////////string class public functions///////////////////////
////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////constructors///////////////////////////////////////
String::String(){//default constructor. default size
arr = new char[stringSize];
cap = stringSize;
arr[0] = 0;
}
String::String(const char a){//char constructor. default size
arr = new char[stringSize];
cap = stringSize;
arr[0] = a;
arr[1] = 0;
}
String::String(const char a[]){//char array constructor. default size
arr = new char[stringSize];
cap = stringSize;
int i = 0;
while (a[i] > 0){
arr[i] = a[i];
++i;
}
arr[i] = 0;
}
String::String(const int initSize, const char a[]){//char array constructor. size passed as a parameter
arr = new char[initSize];
cap = initSize;
int i = 0;
while (a[i] > 0){
arr[i] = a[i];
++i;
}
arr[i] = 0;
}
String::String(int initSize){//like default constructor. size passed as parameter
arr = new char[initSize];
cap = initSize;
}
//////////////////////////////////dynamic stuff/////////////////////////////////////////////////
String::String(const String& rhs){//big three. copy constructor
arr = new char[rhs.cap];
cap = rhs.cap;
for (int i = 0; i < cap; ++i)
arr[i] = rhs.arr[i];
}
String::~String(){//big three. destuctor.
delete [] arr;
}
String& String::operator=(String rhs){//big three. assignment operator.
swap(rhs);
return *this;
}
String String::swap(String& rhs){//swap the pointers on 2 char arrays.
int tmpCap = rhs.cap;
rhs.cap = cap;
cap = tmpCap;
char* tmp = rhs.arr;
rhs.arr = arr;
arr = tmp;
return *this;
}
///////////////////////////////////functions////////////////////////////////////////////////////////////////
void String::reallocate(int a){//changes the size of a dynamic String. size passed as parameter.
String tmp;
tmp.cap = a;
tmp.arr = new char[a];//allocate space of size passed.
int i = 0;
while (arr[i] != 0){//copy elements to newly allocated tmp array
tmp.arr[i] = arr[i];
++i;
}
tmp.arr[i] = 0;
swap(tmp);//swap pointers of tmp and passed array
}
std::vector<String> String::split(char splitter) const{//splits a String into a vecotr of
std::vector<String> vecOfStrings;//Strings besed on the delimited passed
int start = 0, end = 0;//returns that vector
bool doIt = false;
for (int i = 0; i < cap; ++i){//look if the delimiter exists
if (arr[i] == ' '){
doIt = true;
break;
}
}
if (doIt){//if the delimiter exists in the string start looping
for (int i = 0; i < cap; ++i){
if (arr[i] == splitter){//when each occurance of the delimiter is found create a
end = i;//node of String in the vector with the chars since the previous node
vecOfStrings.push_back(substr(start, end - 1));
start = (end + 1);
}
if (i == (cap - 1)){//do this until the no more delimiters are found
end = i;
vecOfStrings.push_back(substr(start, end));
}
}
}
return vecOfStrings;
}
int String::length() const{//returns the length of the String before the terminating char.
int counter = 0;
while (arr[counter] != 0)
++counter;
return counter;
}
int String::capacity() const{//accessor to capacity.
return cap;
}
String String::substr(int start, int end) const{//returns a subset string of string passed.
if ((start < 0) || (end < 0))//parameters are starting and ending points of the substring
return String();
String result;
int returnIndex = start;
for (int i = start; i <= end; ++i)
result[i - start] = arr[returnIndex++];
result[end - start + 1] = 0;
return result;
}
int String::findChar(const char target) const{//returns the position of the first occurance of the char
for (int i = 0; i < length(); ++i)//being searched for. returns -1 if the char is not found.
if (arr[i] == target)
return i;
std::cout << "The char was not found." << std::endl;
return -1;
}
int String::findStr(const char target[]) const{//searches for a substring in the string. returns the
String targetString(target);//position of the first char in the substring
return findStr(targetString);//uses the String version of findStr. look there for more info.
}
int String::findStr(const String& target) const{//searches for a substring in the string. returns the
int targetLength = target.length();//position of the first char in the substring
String candidate;//candidate is the string that
int candStart = 0, candEnd = candStart + (targetLength - 1), i = 0;//will be compared to other strings
//of the same length
while (i < (stringSize - targetLength)){//go through char by char and compare candidate to
candidate = substr(candStart++, candEnd++);//strings of the same length within the full string.
if (candidate == target)//ex String = "Hello World." looking for "llo"
return i;//"Hel" == "llo" no "Hel" == "ell" no "llo == "llo" yes.
i++;//return 2.
}
std::cout << "The string was not found." << std::endl;
return -1;//if not found at all return -1
}
int String::stringToInt(){
int result = 0, intTmp;
char charTmp;
for (int i = 0; i < length(); ++i){
charTmp = arr[i];
switch (charTmp){
case '0' : intTmp = 0; break;
case '1' : intTmp = 1; break;
case '2' : intTmp = 2; break;
case '3' : intTmp = 3; break;
case '4' : intTmp = 4; break;
case '5' : intTmp = 5; break;
case '6' : intTmp = 6; break;
case '7' : intTmp = 7; break;
case '8' : intTmp = 8; break;
case '9' : intTmp = 9; break;
case '-' : intTmp = 0; break;
}
if (result > 0)
result = result * 10;
result = result + intTmp;
}
return result;
}
/////////////////////////////////////////////operators////////////////////////////////////////////////////////////////////
char String::operator[](int i) const{//subscript operator. returns char whated in char array. const version.
return arr[i];//acts as an accessor to chars
}
char& String::operator[](int i){//subscript operator. returns char whated in char array. non const version.
return arr[i];//acts as an accessor to chars
}
String String::operator+(const String& rhs) const{//concatenate
String result(arr);
int start = length(), rhsIndex = 0;
while (rhs.arr[rhsIndex] != 0){
result.arr[start] = rhs.arr[rhsIndex];
start++;
rhsIndex++;
}
result.arr[start] = 0;
return result;
}
bool String::operator==(const String& rhs) const{
if (length() != rhs.length())
return false;
for (int i = 0; i < length(); ++i)
if (arr[i] != rhs.arr[i])
return false;
return true;
}
bool String::operator!=(const String& rhs) const{
if (*this == rhs)
return false;
return true;
}
bool String::operator<(const String& rhs) const{
int i = 0;
while (arr[i] != 0 && rhs.arr[i] != 0){
if ((arr[i] - rhs.arr[i]) < 0)
return true;
else if ((arr[i] - rhs.arr[i]) > 0)
return false;
i++;
}
if (length() < rhs.length())
return true;
return false;
}
bool String::operator>(const String& rhs) const{
if (*this == rhs)
return false;
if (*this < rhs)
return false;
return true;
}
bool String::operator<=(const String& rhs) const{
if (*this == rhs)
return true;
if (*this < rhs)
return true;
return false;
}
bool String::operator>=(const String& rhs) const{
if (*this == rhs)
return true;
if (*this < rhs)
return false;
return true;
}
//////////////////////////////free functions////////////////////////////////
////////////////////////////////////////////////////////////////////////////
///////////////they use the public functions of the String class////////////
String operator+(const char lhs[], const String& rhs){
String lhsString(lhs);
String result = lhsString + rhs;
return result;
}
String operator+(const char lhs, const String& rhs){
String lhsString(lhs);
String result = lhsString + rhs;
return result;
}
bool operator==(const char lhs[], const String& rhs){
String lhsString(lhs);
return lhsString == rhs;
}
bool operator==(const char lhs, const String& rhs){
String lhsString(lhs);
return lhsString == rhs;
}
bool operator!=(const char lhs[], const String& rhs){
String lhsString(lhs);
return lhsString != rhs;
}
bool operator!=(const char lhs, const String& rhs){
String lhsString(lhs);
return lhsString != rhs;
}
bool operator<(const char lhs[], const String& rhs){
String lhsString(lhs);
return lhsString < rhs;
}
bool operator<(const char lhs, const String& rhs){
String lhsString(lhs);
return lhsString < rhs;
}
bool operator>(const char lhs[], const String& rhs){
String lhsString(lhs);
return lhsString > rhs;
}
bool operator>(const char lhs, const String& rhs){
String lhsString(lhs);
return lhsString > rhs;
}
bool operator<=(const char lhs[], const String& rhs){
String lhsString(lhs);
return lhsString <= rhs;
}
bool operator<=(const char lhs, const String& rhs){
String lhsString(lhs);
return lhsString <= rhs;
}
bool operator>=(const char lhs[], const String& rhs){
String lhsString(lhs);
return lhsString >= rhs;
}
bool operator>=(const char lhs, const String& rhs){
String lhsString(lhs);
return lhsString >= rhs;
}
I've added some to the code for debugging purposes. The 6 never appears.
String postfix(String infix){
std::vector<String> vec;
vec = infix.split(' ');
Stack<String> tmp;
String right, left, op;
int i = 0;
while (vec[i] != ';'){
std::cout << 1 << std::endl;
if (vec[i] == ')'){
right = tmp.pop();
op = tmp.pop();
left = tmp.pop();
std::cout << 2 << std::endl;
tmp.push(left + ' ' + right + ' ' + op);
std::cout << 3 << std::endl;
}else{
if (vec[i] != '(' && vec[i] != ' ')
std::cout << 4 << std::endl;
tmp.push(vec[i]);
std::cout << 5 << std::endl;
}
++i;
}
std::cout << 6 << std::endl;
String postfix = tmp.pop();
return postfix;
}
Output is
-bash-4.1$ make tests
g++ -g -Wall -W -Wunused -Wuninitialized -Wshadow -iquote . -iquote ../string -c test_data3.cpp
g++ -g -Wall -W -Wunused -Wuninitialized -Wshadow string.o test_data3.o -o test_data3
./test_intStack
Everything looks good. Done testing an int Stack.
./test_stringStack
Everything looks good. Done testing a String Stack.
./test_data3
( AX + ( B * C ) ) ;
1
5
1
4
5
1
4
5
1
5
1
4
5
1
4
5
1
4
5
1
2
3
1
2
3
1
4
5
make: * [tests] Segmentation fault (core dumped)
rm test_data3.o
You almost certainly want to start by isolating the problem.
To do that, I'd start by doing a bit of rewriting to use your own code for the postfix conversion itself, but use std::string and std::stack for the string and stack type respectively.
If that makes the problem disappear, switch one (but not both) back to use your class. If it still works, switch the other to use your class.
Chances are very good that this will fairly quickly tell you whether the problem is in your postfix-conversion, your Stack, or your String. Once you've figured that out, I'd probably work at writing some decent unit tests for the component in question.
You could just debug it in context instead, but chances are pretty fair (at least in my experience) that doing so will often leave a number of similar problems, so the next time you try to use it, you'll run into similar problems under slightly different circumstances. By working at it more systematically you can eliminate entire classes of bugs instead of removing them one at a time.
I'm sorry if this is a very basic question, I'm pretty new to C++.
I'm trying to define my own vector class and an iterator for it. However, whenever I overload an operator the value that is returned is always an address.
For instance, the following code prints 0x7fb6dbc000e0 0x7fb6dbc000e0 when I want it to print 1 0
Since I've been messing around with the syntax for a while, some of the operators look a little different, this is just so that you can see a few things I've tried.
test.cc
#include <iostream>
#include "TwoWayVector.cc"
int main(){
TwoWayVector<int> numbers;
numbers.push_back(3);
numbers.push_back(2);
TwoWayVectorIterator<int>* beginning = numbers.begin();
TwoWayVectorIterator<int>* beginning2 = numbers.begin();
cout << beginning==beginning2;
cout << beginning != beginning2;
cout << endl;
return 0;
}
TwoWayVector.cc
using namespace std;
#include "TwoWayVectorIterator.cc"
template <class T> class TwoWayVector{
public:
T* data;
int capacity;
int nextFree;
TwoWayVector(){
capacity = 10;
nextFree = 0;
data = new T[capacity];
}
~TwoWayVector(){
delete data;
}
T& operator[](const int index){
if( index >= capacity || capacity + index < 0){
string number = static_cast<ostringstream*>( &(ostringstream() << index) )->str();
string error = "index " + number + " is out of bounds";
throw error;
}
else if(index < 0){
return data[nextFree+index];
}
return data[index];
}
bool operator==(const TwoWayVector* vector2){
if(capacity != vector2->capacity){
return false;
}
if(nextFree != vector2->nextFree){
return false;
}
for(int i=0; i<nextFree ; i++){
if(data[i] != vector2[i]){
return false;
}
}
return true;
}
//memory leaks?
void push_back(T object){
if(capacity <= nextFree){
capacity = capacity*2;
T* tmp = new T[capacity];
for(int i=0; i<capacity; i++){
tmp[i] = data[i];
}
delete data;
data = tmp;
}
data[nextFree] = object;
nextFree++;
}
T pop_back(){
nextFree--;
T result = data[nextFree];
data[nextFree] = NULL;
return result;
}
int size(){
return nextFree;
}
TwoWayVectorIterator<T>* begin(){
TwoWayVectorIterator<T>* i = new TwoWayVectorIterator<T>(0,this);
return (i);
}
TwoWayVectorIterator<T>* end(){
TwoWayVectorIterator<T>* i = new TwoWayVectorIterator<T>(nextFree,this);
return(i);
}
};
TwoWayVectorIterator.cc
template<typename T> class TwoWayVector;
template <class T> class TwoWayVectorIterator{
public:
TwoWayVector<T>* vector;
int currentPosition;
TwoWayVectorIterator(TwoWayVector<T>& vec){
currentPosition = 0;
vector = vec;
}
TwoWayVectorIterator( int pos , TwoWayVector<T>* vec){
currentPosition = pos;
vector = vec;
}
bool operator==(const TwoWayVectorIterator* vector2){
bool contents, position;
contents = (vector == vector2) ? true : false;
cout << contents << endl;
position =(currentPosition == vector2->currentPosition) ? true : false;
return (contents && position);
}
bool& operator!=(const TwoWayVectorIterator* vector2){
bool contents, position;
contents = (vector == vector2) ? false : true;
position=(currentPosition == vector2->currentPosition) ? false : true;
return (contents || position);
}
TwoWayVectorIterator& operator++(){
return *this;
currentPosition = (currentPosition+1);
}
TwoWayVectorIterator& operator++(int){
currentPosition = (currentPosition+1);
return *this;
}
TwoWayVectorIterator& operator=(TwoWayVectorIterator* vector2){
&vector = vector2;
currentPosition = vector2->currentPosition;
return *this;
}
TwoWayVectorIterator& operator+(int n){
currentPosition = currentPosition+n;
return *this;
}
TwoWayVectorIterator& operator-(int n){
currentPosition = currentPosition-n;
return *this;
}
bool& operator<(TwoWayVectorIterator* vector2){
return (currentPosition<vector2->currentPosition);
}
T& operator*(){
return vector[currentPosition];
}
};
cout << beginning==beginning2;
does not mean
cout << (beginning==beginning2);
It does mean
(cout << beginning) == beginning2;
http://en.cppreference.com/w/cpp/language/operator_precedence
Therefore you are printing a TwoWayVectorIterator<int>*, not a bool.
The precedence of the << operator is higher then the precedence of the == and != operator. So
cout << beginning==beginning2;
cout << beginning != beginning2;
really means
(cout << beginning)==beginning2;
(cout << beginning) != beginning2;
Try
cout << (beginning==beginning2);
cout << (beginning) != beginning2);