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.
Related
I am trying to write a basic string class for practice, and I am struggling with the reserve() function to increase my char array's memory allocation.
This is the error message I get:
free(): double free detected in tcache 2
This is my approach:
void string::reserve(size_t n)
{
if (n <= space+1) return; // never decrease allocation
char *p = new char[n+1]; // allocate new space
for (int i=0; i<sz; ++i) p[i]=pChars[i]; // copy old elements
//strcpy(p, pChars); // didn't work either
p[n] = '\0';
delete[] pChars; // deallocate old space
pChars = p;
space = n+1;
}
I will also share a picture of my header file below:
Here is the entire code:
#include "String.h"
namespace String
{
string::string(): sz(0), pChars(nullptr), space(0) {}
string::string(const char* s): sz(strlen(s)), pChars(new char[strlen(s)+1]), space(sz+1) ///Constructor using a null-terminated C String
{
//for (int i = 0; s[i] != '\0'; i++) pChars[i] = s[i];
strcpy(pChars,s);
pChars[strlen(s)] = '\0';
}
string::string(const string& s): sz(s.sz), pChars(new char[s.sz]), space(s.sz) ///copy constructor
{
for (size_t i = 0 ; i<s.sz; i++) pChars[i] = s.pChars[i];
pChars[s.sz] = '\0';
}
string& string::operator=(const string& s) ///copy assignment
{
if (this==&s) return *this; // self-assignment, no work needed
if (s.sz<=space)
{ // enough space, no need for new allocation
for (size_t i = 0; i<s.sz; ++i) pChars[i] = s.pChars[i]; // copy elements
sz = s.sz;
return *this;
}
char *p = new char [s.sz]; // copy and swap
for (size_t i = 0; i<s.sz; ++i) p[i] = s.pChars[i];
delete[] pChars;
sz = s.sz;
space = s.sz;
pChars = p;
return *this;
}
string& string:: operator=(const char* s) ///copy assignment using a null-terminated C String
{
char *p = new char[strlen(s)+1];
for(size_t i = 0; s[i] != '\0'; i++) p[i] = s[i];
p[sz] = '\0';
delete [] pChars;
sz = strlen(s);
space = sz;
strcpy(pChars, p);
return *this;
}
///string(string&& s); ///move constructor, not needed (compiler copy elision)
string& string:: operator=(string&& s) ///move assignment
{
delete[] pChars; // deallocate old space
pChars = s.pChars; // copy a's elem and sz
sz = s.sz;
space = s.space;
s.pChars = nullptr; // make a the empty vector
s.sz = 0;
cout << "Move" << endl;
return *this;
}
string::~string()
{
delete [] pChars;
}
char& string:: operator[](size_t pos) {return pChars[pos];} ///set operator
const char& string:: operator[](size_t pos) const {return pChars[pos];} ///get operator
void string::reserve(size_t n)
{
if (n <= space+1) return; // never decrease allocation
char *p = new char[n+1]; // allocate new space
for (int i=0; i<sz; ++i) p[i]=pChars[i]; // copy old elements
//strcpy(p, pChars);
p[sz] = '\0';
delete[] pChars; // deallocate old space
pChars = p;
space = n+1;
}
void string:: push_back(const char c) ///push char c to the end
{
if (sz==0) // no space: grab some
reserve(8);
else if (sz==space) // no more free space: get more space
reserve(2*space);
pChars[sz] = c; // add d at end
++sz; // and increase the size (sz is the number of elements)
}
bool operator==(const string& lhs, const string& rhs) ///check equality (same size, all chars the same)
{
if (lhs.size() != rhs.size()) return false;
else
{
for (size_t i = 0; i<lhs.size(); i++)
{
if (lhs[i] != rhs[i]) return false;
}
}
return true;
}
bool operator==(const string& lhs, const char* rhs) ///equality with null terminated C string
{
if(lhs.size() == strlen(rhs))
{
for (size_t i = 0; i< lhs.size(); i++)
{
if(lhs[i] == rhs[i]) return true;
}
}
return false;
}
bool operator>(const string& lhs, const string& rhs) ///greater than operator, true if lhs > rhs
{
}
string operator+(const string& lhs, const string& rhs) ///concatenate two MyStrings, return the result
{
}
ostream& operator<<(ostream& os, const string& s)
{
for (size_t i = 0; i<s.size(); i++)
{
os << s[i];
}
return os;
}
istream& operator>>(istream& is, string& s)
{
char c;
while(is.get(c))
{
if (c!=' ') s.push_back(c);
}
return is;
}
}
First error
string::string(const string& s): sz(s.sz), pChars(new char[s.sz]), space(s.sz) ///copy constructor
{
for (size_t i = 0 ; i<s.sz; i++) pChars[i] = s.pChars[i];
pChars[s.sz] = '\0';
}
This allocates an array of s.sz chars and then writes off the end of it
SHould be
string::string(const string& s): sz(s.sz), pChars(new char[s.sz] + 1), space(s.sz) ///copy constructor
{
for (size_t i = 0 ; i<s.sz; i++) pChars[i] = s.pChars[i];
pChars[s.sz] = '\0';
}
i've been absolutely lost on this topic. I wrote my own String class and tried running it in valgrind to see of it really works. Valgrind tells me that i got a lot of invalid read's and write's.
Basically what im trying to do is feed it a String Value and read it's contents later on. For this i defined following Header file.
#ifndef STRING_H_INCLUDED
#define STRING_H_INCLUDED
#include<iostream>
#include<istream>
#include<ostream>
class string{
public:
string(char* = nullptr);
~string();
string(const string&);
friend std::istream& operator>>(std::istream&,string&);
friend std::ostream& operator<<(std::ostream&,string&);
bool operator<(const string&);
bool operator==(const string&);
void setContent(char*);
char* getContent() const;
private:
unsigned getSize() const;
void copyStr(char*,char*);
unsigned getCharl(const char*)const;
string& operator=(const string&);
char* s = nullptr;
};
#endif // STRING_H_INCLUDED
The CPP for the Header looks like the following.
#include<iostream>
#include<ostream>
#include "string.h"
string::string(char* i){
if(i == nullptr){
s = new char[1];
s[0] = '\0';
}else{
s = new char[getCharl(i)+1];
copyStr(s,i);
}
}
string::~string(){
if(s != nullptr){
delete s;
}
}
unsigned string::getCharl(const char* i) const{
const char* ende = i;
for(; *ende != '\0';++ende)
;
return ende-i;
}
void string::copyStr(char* s,char* i){
unsigned index = 0;
s = new char[getCharl(i)+1];
while (i[index] != '\0'){
s[index] = i[index];
index++;
}
s[index] = '\0';
}
bool string::operator<(const string& s1){
if(getSize()<s1.getSize()){
return true;
}else if(getSize()>s1.getSize()){
return false;
}else{
for(unsigned i = 0; i < s1.getSize();++i){
if(getContent()[i] != s1.getContent()[i]){
if(getContent()[i]<s1.getContent()[i]){
return true;
}else{
return false;
}
}
}
return false;
}
}
string::string(const string& x){
delete s;
s = new char[x.getSize()];
char* tmp = x.getContent();
unsigned index = 0;
while (tmp[index] != '\0'){
this->s[index] = x.s[index];
index++;
}
}
char* string::getContent() const{
return s;
}
void string::setContent(char* v){
s = v;
}
string& string::operator=(const string& x){
if(this == &x)
return *this;
if(&x != this){
delete getContent();
setContent(nullptr);
setContent(new char[x.getSize()]);
}
copyStr(getContent(),x.getContent());
return *this;
}
bool string::operator==(const string& l){
if(getSize() == l.getSize()){
unsigned length = getSize();
for(unsigned i = 0; i < length;++i){
if(getContent()[i] != l.getContent()[i])
return false;
}
return true;
}
return false;
}
std::istream& operator>>(std::istream& is, string& arg){
return is >> arg.s;
}
std::ostream& operator<<(std::ostream& os, string& arg){
return os << arg.getContent();
}
unsigned string::getSize() const{
unsigned length = 0;
while(s[length]){
++length;
}
++length;
return length;
}
Basically i would be pretty happy to know why i get an error in my operator>> where i try to write a char* Array to my char* s.
And i would like to know why i get an error in my function getSize() in the while-loop. (Error appears at s[length]).
Maybe someone is so kind to explain me the reasons.
Cheers!
Edit:
Modified the program now to look like the following implementing the comments.
#include<iostream>
#include<ostream>
#include "string.h"
string::string(char* i){
if(i == nullptr){
s = new char[1];
s[0] = '\0';
}else{
s = new char[getCharl(i)+1];
copyStr(i);
}
}
string::~string(){
if(s != nullptr){
delete[] s;
}
}
unsigned string::getCharl(const char* i) const{
const char* ende = i;
for(; *ende != '\0';++ende)
;
return ende-i;
}
void string::copyStr(char* i){
unsigned index = 0;
delete[] s;
char* tmp = new char[getCharl(i)+1];
while (i[index] != '\0'){
tmp[index] = i[index];
index++;
}
tmp[index] = '\0';
s = tmp;
}
bool string::operator<(const string& s1){
if(getSize()<s1.getSize()){
return true;
}else if(getSize()>s1.getSize()){
return false;
}else{
for(unsigned i = 0; i < s1.getSize();++i){
if(getContent()[i] != s1.getContent()[i]){
if(getContent()[i]<s1.getContent()[i]){
return true;
}else{
return false;
}
}
}
return false;
}
}
string::string(const string& x){
copyStr(x.getContent());
}
char* string::getContent() const{
return s;
}
void string::setContent(char* v){
s = v;
}
string& string::operator=(const string& x){
if(this == &x)
return *this;
if(&x != this){
delete[] getContent();
setContent(nullptr);
setContent(new char[x.getSize()]);
}
copyStr(x.getContent());
return *this;
}
bool string::operator==(const string& l){
if(getSize() == l.getSize()){
unsigned length = getSize();
for(unsigned i = 0; i < length;++i){
if(getContent()[i] != l.getContent()[i])
return false;
}
return true;
}
return false;
}
std::istream& operator>>(std::istream& is, string& arg){
is >> arg.s;
return is;
}
std::ostream& operator<<(std::ostream& os, string& arg){
return os << arg.getContent();
}
unsigned string::getSize() const{
unsigned length = 0;
while(getContent()[length]){
++length;
}
++length;
return length;
}
Still the problem with the operator>> exists and also now im getting errors in getCharl in the for loop and copyStr im the while loop. (invalid read)
If someone would be so kind and explain to me why.
This is the code for my project which I want to compile. The error is stated at the end of the question.
#include <iostream>
#include <string>
#include <stdio.h>
class substring {
friend std::ostream& operator<<(std::ostream& output, substring const& sub);
public:
char *str;
int length;
substring();
~substring();
substring(std::string);
substring(const substring &);
substring& operator=(substring const& other);
substring& operator=(std::string const& strz);
substring& operator+=(substring const& other);
bool operator>(substring const& other) const;
bool operator<(substring const& other) const;
char& operator[](size_t idx);
char operator[](size_t idx) const;
};
std::ostream& operator<<(std::ostream& output, substring const& sub);
std::istream& operator >> (std::istream& input, substring const& sub);
bool operator==(substring const& one, substring const& another);
bool operator!=(substring const& one, substring const& another);
bool operator==(std::string const& str, substring const& sub);
bool operator==(substring const& sub, std::string const& str);
bool operator!=(std::string const& str, substring const& sub);
bool operator!=(substring const& sub, std::string const& str);
substring::substring()
{
length = 0;
}
substring::~substring()
{
delete str;
}
substring::substring(std::string)
{
}
substring::substring(const substring & sub)
{
str = new char[length];
}
std::ostream & operator<<(std::ostream & output, substring const & sub)
{
output << sub;
return output;
}
std::istream & operator >> (std::istream & input, substring const & sub)
{
std::cout << "Enter sub:";
input >> sub;
return input;
}
bool operator==(substring const & one, substring const & another)
{
if (one.length != another.length)
return false;
else
{
for (int i = 0; i < another.length; i++)
if (one[i] != another[i])
{
return false;
break;
}
}
return true;
}
bool operator!=(substring const & one, substring const & another)
{
if (one.length != another.length)
return true;
else
{
for (int i = 0; i < another.length; i++)
if (one[i] != another[i])
{
return true;
break;
}
}
return false;
}
bool operator==(std::string const & str, substring const & sub)
{
if (sub.length != str.length())
return false;
else
{
for (int i = 0; i < sub.length; i++)
if (str[i] != sub[i])
{
return false;
break;
}
}
return true;
}
bool operator==(substring const & sub, std::string const & str)
{
if (str.length() != sub.length)
return false;
else
{
for (unsigned int i = 0; i < str.length(); i++)
if (sub[i] != str[i])
{
return false;
break;
}
}
return true;
}
bool operator!=(std::string const & str, substring const & sub)
{
if (sub.length != str.length())
return true;
else
{
for (int i = 0; i < sub.length; i++)
if (str[i] != sub[i])
{
return true;
break;
}
}
return false;
}
bool operator!=(substring const & sub, std::string const & str)
{
if (sub.length != str.length())
return true;
else
{
for (int i = 0; i < sub.length; i++)
if (str[i] != sub[i])
{
return true;
break;
}
}
return false;
}
substring & substring::operator=(substring const & other)
{
delete str;
length = other.length;
str = new char[length];
for (int i = 0; i<length; i++)
{
str[i] = other.str[i];
}
return *this;
}
substring & substring::operator=(std::string const & strz)
{
length = strz.length();
str = new char[length];
for (int i = 0; i<length; i++)
{
str[i] = strz[i];
}
return *this;
}
substring & substring::operator+=(substring const & other)
{
char* new_str = new char[length + other.length];
for (int i = 0; i<length; i++)
{
new_str[i] = str[i];
}
for (int i = length; i<other.length; i++)
{
new_str[i] = other.str[i];
}
delete str;
str = new_str;
return *this;
}
bool substring::operator>(substring const & other) const
{
return true;
}
bool substring::operator<(substring const & other) const
{
return true;
}
char & substring::operator[](size_t idx)
{
return str[idx];
}
char substring::operator[](size_t idx) const
{
return str[idx];
}
int main()
{
std::string str = "abc";
substring sub = str;
std::cout << sub;
return 0;
}
The problem is that when I run this code, it seems that the compiler just skips this: substring sub = str;.
I cannot even change this line to substring sub = "aaa"; because it shows an error which says I cannot convert subtring to std::string (although there is an operation overloading for this in the code).
The problem is that when I run this code, it seems that the compiler just skips this: substring sub = str;
The compiler did not "skip it". It compiled succesfully, and the new object was created succesfully. However, the converting constructor that you defined leaves the objects members default initialized:
substring::substring(std::string)
{
}
I cannot even change this line to substring sub = "aaa"; because it shows an error which says I cannot convert subtring to std::string
I highly doubt that. I suspect that you misread.
My compiler says that const char [4] cannot be converted substring
(although there is an operation overloading for this in the code).
There certainly isn't a substring::substring(const char(&)[4]) (nor substring::substring(const char*)).
Hello I am getting compile errors and I don't understand why
2 IntelliSense: expected an identifier c:\Users\Sean\Documents\Visual Studio 2013\Projects\mystring\mystring\mystring.cpp 93 7 mystring
3 IntelliSense: expected a ';' c:\Users\Sean\Documents\Visual Studio 2013\Projects\mystring\mystring\mystring.cpp 93 10 mystring
4 IntelliSense: member function "main_savitch_4::mystring::operator=" may not be redeclared outside its class c:\Users\Sean\Documents\Visual Studio 2013\Projects\mystring\mystring\mystring.cpp 106 17 mystring
5 IntelliSense: expected a ';' c:\Users\Sean\Documents\Visual Studio 2013\Projects\mystring\mystring\mystring.cpp 107 2 mystring
6 IntelliSense: more than one operator ">>" matches these operands:
function "operator>>(std::istream &ins, main_savitch_4::mystring &target)"
function "main_savitch_4::operator>>(std::istream &ins, main_savitch_4::mystring &target)"
operand types are: std::istream >> main_savitch_4::mystring c:\Users\Sean\Documents\Visual Studio 2013\Projects\mystring\mystring\mystring.cpp 246 7 mystring
#include <iostream>
#include "mystring.h"
#include <cstring>
using namespace std;
using namespace main_savitch_4;
//Constructors- sets initial values for memeber variables
mystring::mystring(const char str[] = "")
//returns a pointer referencing [0] in an array
{
current_length = 0;
int pt = 0;
if (str[pt] != '\0') //this increases the array size to the string size
{
++current_length;
++pt;
}
sequence = new char[current_length + 1];
while (current_length >= pt)
{
sequence[pt] = str[pt];
++pt;
}
allocated = current_length + 1;
}
mystring::mystring(const mystring& source)
{
sequence = new char[source.allocated];
current_length = source.current_length; //returns mystring object with same
allocated = source.allocated; //length and allocation as source
for (int i = 0; i <= allocated; ++i)
{
sequence[i] = source.sequence[i]; //copies characters to new object
}
}
//Destructor- frees space
mystring::~mystring()
{
delete[] sequence;
}
void mystring::operator +=(const mystring& addend)//adds another string ontop of the original
{
reserve(current_length + addend.current_length + 1);
strcpy(sequence + current_length, addend.sequence);
current_length += addend.current_length;
}
void mystring::operator +=(const char addend[])
{
int leng = current_length + strlen(addend);
if (leng >= allocated)
{
reserve(leng + 1);
}
strcpy(sequence + current_length, addend);
current_length = leng;
}
void mystring::operator +=(char addend)
{
while (current_length >= allocated)
{
reserve(current_length + 1);
}
sequence[current_length] = addend;
sequence[current_length + 1] = '\0'; //increases size to allow for \0 character
++current_length;
}
void mystring::reserve(size_t n) //size_t represents the size of object
// n is the size
{
if (allocated < n)
{
char[] sequence = new char[n];
for (int i = 0; i <= current_length; ++i)
{
sequence + i;
allocated = n;
}
}
/////////////////////
void mystring::operator =(const mystring& source)
{
delete[] sequence;
sequence = new char[source.allocated];
allocated = source.allocated;
current_length = source.current_length;
for (int idx = 0; idx <= source.allocated; ++idx)
{
sequence[idx] = source.sequence[idx];
}
}
char mystring::operator [ ](size_t position) const
{
return sequence[position];
}
std::ostream& operator <<(std::ostream& outs, const mystring& source)
{
outs << source.sequence;
return outs;
}
bool operator ==(const mystring& s1, const mystring& s2)
{
int length = 0;
bool gate = false;
if (s1.length() >= s2.length())
length = s1.length();
else
length = s2.length();
for (int idx = 0; idx < length; ++idx)
{
if (s1[idx] - s2[idx] == 0 && idx == length - 1)
gate = true;
}
return gate;
}
bool operator !=(const mystring& s1, const mystring& s2)
{
return !(s1 == s2);
}
bool operator >=(const mystring& s1, const mystring& s2)
{
if (s1 < s2)
return false;
else
return true;
}
bool operator <=(const mystring& s1, const mystring& s2)
{
if (s1 > s2)
return false;
else
return true;
}
bool operator > (const mystring& s1, const mystring& s2)
{
bool gate = false;
int length = 0;
if (s1.length() <= s2.length())
length = s1.length();
else if (s1.length() > s2.length())
length = s2.length();
for (int idx = 0; idx < length; ++idx)
{
if (s1[idx] - s2[idx] < 0)
{
gate = true;
idx = length;
}
else if (idx == length - 1 && s1.length() < s2.length())
{
gate = true;
}
}
return gate;
}
bool operator < (const mystring& s1, const mystring& s2)
{
if (s1 != s2 && s2 > s1)
return true;
return false;
}
mystring operator +(const mystring& s1, const mystring& s2)
{
mystring temp(s1);
temp += s2;
return temp;
}
std::istream& operator >>(std::istream& ins, mystring& target)
{
while (ins && isspace(ins.peek()))
{
ins.ignore();
}
target = ""; //Clear out any junk in the target
while (ins.peek() != '\n')
target += ins.get();
return ins;
}
std::istream& getline(std::istream& ins, mystring& target)
{
ins >> target;
return ins;
}
This if statement in function reserve:
void mystring::reserve(size_t n)
{
if (allocated < n)
{
char[] sequence = new char[n];
for (int i = 0; i <= current_length; ++i)
{
sequence + i;
allocated = n;
}
}
Doesn't appear to be closed. Try adding a }.
Here are the full codes that I am using to implement this program. Everything seems to compile and run, but once it runs my find method, the program seems to stop and does not execute the last line stating the matching substring within the main.cpp file. Any help is definitely appreciated!
.h file:
#include <iostream>
using namespace std;
class MyString
{
public:
MyString();
MyString(const char *message);
MyString(const MyString &source);
~MyString();
const void Print() const;
const int Length() const;
MyString& operator()(const int index, const char b);
char& operator()(const int i);
MyString& operator=(const MyString& rhs);
bool operator==(const MyString& other) const;
bool operator!=(const MyString& other) const;
const MyString operator+(const MyString& rhs) const;
MyString& operator+=(const MyString& rhs);
friend ostream& operator<<(ostream& output, const MyString& rhs);
const int Find(const MyString& other);
MyString Substring(int start, int length);
private:
char *String;
int Size;
};
istream& operator>>(istream& input, MyString& rhs);
.cpp file:
#include <iostream>
#include <cstdlib>
#include "MyString.h"
using namespace std;
//default constructor that sets the initial string to the value "Hello World"
MyString::MyString()
{
char temp[] = "Hello World";
int counter(0);
while(temp[counter] != '\0')
{
counter++;
}
Size = counter;
String = new char [Size];
for(int i=0; i < Size; i++)
String[i] = temp[i];
}
//alternate constructor that allows for setting of the inital value of the string
MyString::MyString(const char *message)
{
int counter(0);
while(message[counter] != '\0')
{
counter++;
}
Size = counter;
String = new char [Size];
for(int i=0; i < Size; i++)
String[i] = message[i];
}
//copy constructor
MyString::MyString(const MyString &source)
{
int counter(0);
while(source.String[counter] != '\0')
{
counter++;
}
Size = counter;
String = new char[Size];
for(int i = 0; i < Size; i++)
String[i] = source.String[i];
}
//Deconstructor
MyString::~MyString()
{
delete [] String;
}
//Length() method that reports the length of the string
const int MyString::Length() const
{
int counter(0);
while(String[counter] != '\0')
{
counter ++;
}
return (counter);
}
/*Parenthesis operator should be overloaded to replace the Set and Get functions of your previous assignment. Note that both instances should issue exit(1) upon violation of the string array bounaries.
*/
MyString& MyString::operator()(const int index, const char b)
{
if(String[index] == '\0')
{
exit(1);
}
else
{
String[index] = b;
}
}
char& MyString::operator()(const int i)
{
if(String[i] == '\0')
{
exit(1);
}
else
{
return String[i];
}
}
/*Assignment operator (=) which will copy the source string into the destination string. Note that size of the destination needs to be adjusted to be the same as the source.
*/
MyString& MyString::operator=(const MyString& rhs)
{
if(this != &rhs)
{
delete [] String;
String = new char[rhs.Size];
Size = rhs.Size;
for(int i = 0; i < rhs.Size+1 ; i++)
{
String[i] = rhs.String[i];
}
}
return *this;
}
/*Logical comparison operator (==) that returns true iff the two strings are identical in size and contents.
*/
bool MyString::operator==(const MyString& other)const
{
if(other.Size == this->Size)
{
for(int i = 0; i < this->Size+1; i++)
{
if(&other == this)
return true;
}
}
else
return false;
}
//Negated logical comparison operator (!=) that returns boolean negation of 2
bool MyString::operator!=(const MyString& other) const
{
return !(*this == other);
}
//Addition operator (+) that concatenates two strings
const MyString MyString::operator+(const MyString& rhs) const
{
char* tmp = new char[Size + rhs.Size +1];
for(int i = 0; i < Size; i++)
{
tmp[i] = String[i];
}
for(int i = 0; i < rhs.Size+1; i++)
{
tmp[i+Size] = rhs.String[i];
}
MyString result;
delete [] result.String;
result.String = tmp;
result.Size = Size+rhs.Size;
return result;
}
/*Addition/Assigment operator (+=) used in the following fashion: String1 += String2 to operate as String1 = String1 + String2
*/
MyString& MyString::operator+=(const MyString& rhs)
{
char* tmp = new char[Size + rhs.Size + 1];
for(int i = 0; i < Size; i++)
{
tmp[i] = String[i];
} for(int i = 0; i < rhs.Size+1; i++)
{
tmp[i+Size] = rhs.String[i];
}
delete [] String;
String = tmp;
Size += rhs.Size;
return *this;
}
istream& operator>>(istream& input, MyString& rhs)
{
char* t;
int size(256);
t = new char[size];
input.getline(t,size);
rhs = MyString(t);
delete [] t;
return input;
}
ostream& operator<<(ostream& output, const MyString& rhs)
{
if(rhs.String != '\0')
{
output << rhs.String;
}
else
{
output<<"No String to output\n";
}
return output;
}
const int MyString::Find(const MyString& other)
{
int nfound = -1;
if(other.Size > Size)
{
return nfound;
}
int i = 0, j = 0;
for(i = 0; i < Size; i++)
{
for(j = 0; j < other.Size; j++)
{
if( ((i+j) >= Size) || (String[i+j] != other.String[j]) )
{
break;
}
}
if(j == other.Size)
{
return i;
}
}
return nfound;
}
/*MyString::Substring(start, length). This method returns a substring of the original string that contains the same characters as the original string starting at location start and is as long as length.
*/
MyString MyString::Substring(int start, int length)
{
char* sub;
sub = new char[length+1];
while(start != '\0')
{
for(int i = start; i < length+1; i++)
{
sub[i] = String[i];
}
}
return MyString(sub);
}
//Print() method that prints the string
const void MyString::Print() const
{
for(int i=0; i < Size; i++)
{
cout<<String[i];
}
cout<<endl;
}
main.cpp file:
#include <cstdlib>
#include <iostream>
#include "MyString.h"
using namespace std;
/*
*
*/
int main (int argc, char **argv)
{
MyString String1; // String1 must be defined within the scope
const MyString ConstString("Target string"); //Test of alternate constructor
MyString SearchString; //Test of default constructor that should set "Hello World". W/o ()
MyString TargetString (String1); //Test of copy constructor
cout << "Please enter two strings. ";
cout << "Each string needs to be shorter than 256 characters or terminated by /\n." << endl;
cout << "The first string will be searched to see whether it contains exactly the second string. " << endl;
cin >> SearchString >> TargetString; // Test of cascaded string-extraction operator
if(SearchString.Find(TargetString) == -1) {
cout << TargetString << " is not in " << SearchString << endl;
}
else {
cout << TargetString << " is in " << SearchString << endl;
cout << "Details of the hit: " << endl;
cout << "Starting poisition of the hit: " << SearchString.Find(TargetString) << endl;
cout << "The matching substring is: " << SearchString.Substring(SearchString.Find(TargetString), TargetString.Length());
}
return 0;
}
It appears the inner loop's invariant is that j is between 0 and end-2 inclusive. Hence j will NEVER equal end (the "matching" condition).
Looks like you have a problem with your found logic.
Your for loop is defined as for(int j = 0; j < end -1; j++)
but then you test for if(j == end)
j can never be equal to end in this for loop. Consider what you're actually trying to test for in your if statement.
I think you need to declare i and j outside the loops.
I think you meant j < end and not j < end - 1
I think you need to if((i+j>=end1) || String[i+j] != other.String[j]) and not just if(String[i+j] != other.String[j])
and if(j == end) needs to be outside the inner loop.
Here is a similar implementation.
#include <string>
#include <iostream>
using namespace std;
class MyString
{
private:
string String;
unsigned int Size;
public:
MyString() {
this->String = "";
this->Size = 0;
}
MyString(string initial_value) {
this->String = initial_value;
this->Size = initial_value.length();
}
const int Find(const MyString& other);
};
const int MyString::Find(const MyString& other)
{
if (other.Size > Size)
return -1; // if the substring is greater then us, there's no way we can have it as a substring
int i = 0, j = 0;
for (i = 0; i < Size; i++)
{
for (j = 0; j < other.Size; j++)
if ( ((i + j) >= Size) || (String[i + j] != other.String[j]) ) // if they don't match, offset exceeded Size, break
break ;
if (j == other.Size) // We went through the entire substring, didn't hit break so j == Other.size
return i; // return index
}
return -1; // if we never return anything means, we didn't find it, so return -1
}
int main()
{
string temp1, temp2;
getline(std::cin, temp1, '\n');
getline(std::cin, temp2, '\n');
MyString main_string(temp1), sub_string(temp2);
cout << main_string.Find(sub_string) << endl;
return 0;
}
MyString MyString::Substring(int start, int length)
{
char* sub = new char[length + 2]; // 2 byte buffer to be safe
int i = 0;
for (i = 0; i < length; i++)
sub[i] = String[start + i];
sub[i] = '\0'; // always null terminated to be safe!
return MyString(sub);
}
if theres any bugs or issues, I apologize, haven't tested it.
Along with what everyone else said, in your Substring method you have the following bit of code:
while(start != '\0')
{
for(int i = start; i < length+1; i++)
{
sub[i] = String[i];
}
}
Take a moment to go over the logic of the while loop and ask yourself "what am I trying to achieve here, and what does this code actually do?"