I am having trouble getting my string class working. My istream function seems to read the data in, and I confirmed that the += was adding the characters, but after the first character, what is added is garbage. I have tried everything I can think of to get it working. Can someone please provide some insight as to what is going wrong. Thanks.
istream& operator >>(istream& ins, string& target)
{
char newInput;
while (ins && isspace(ins.peek()))
ins.ignore();
target = ("");
//int count = 0;
while (ins && !isspace(ins.peek())) //(ins.peek())))
{
ins >> newInput;
target.operator+=(newInput);
}
return ins;
}
void string::operator +=(char addend)
{
if (this->current_length + 1 > this->allocated)
{
reserve(allocated + 1);
}
sequence[current_length] = addend;
current_length += 1;
}
void string::reserve(size_t n)
{
assert(n > current_length);
char *newSequence = new char[n];
if (n == allocated)
{
return;
}
for (size_t i = 0; i < n; i++)
{
newSequence[i] = sequence[i];
}
//destroy old array
delete[] sequence;
//update capacity
allocated = n;
//point data at new array
sequence = newSequence;
}
Full Code: **
#pragma warning(disable : 4996)
#ifndef MAIN_SAVITCH_CHAPTER4_MYSTRING_H
#define MAIN_SAVITCH_CHAPTER4_MYSTRING_H
#include <cstdlib> // Provides size_t
#include <cassert>
#include <string.h>
#include <iostream>
#include <ctype.h>
#include <algorithm>
using namespace std;
namespace main_savitch_4
{
class string
{
public:
// CONSTRUCTORS and DESTRUCTOR
string(const char str[] = "");
string(const string& source);
~string() { delete[] sequence; }
// MODIFICATION MEMBER FUNCTIONS
void operator +=(const string& addend);
void operator +=(const char addend[]);
void operator +=(char addend);
void reserve(size_t n);
void operator =(const string& source);
// CONSTANT MEMBER FUNCTIONS
size_t length() const { return current_length; }
char operator [ ](size_t position) const;
// FRIEND FUNCTIONS
friend ostream& operator <<(ostream& outs, const string& source);
friend bool operator ==(const string& s1, const string& s2);
friend bool operator !=(const string& s1, const string& s2);
friend bool operator >=(const string& s1, const string& s2);
friend bool operator <=(const string& s1, const string& s2);
friend bool operator > (const string& s1, const string& s2);
friend bool operator < (const string& s1, const string& s2);
private:
char *sequence;
size_t allocated;
size_t current_length;
};
// CONSTRUCTOR for the string class:
// string(const char str[ ] = "") -- default argument is the empty string.
// Precondition: str is an ordinary null-terminated string.
// Postcondition: The string contains the sequence of chars from str.
string::string(const char str[])
{
current_length = strlen(str);
allocated = current_length + 1;
sequence = new char[allocated];
for (size_t i = 0; i < allocated; i++)
{
sequence[i] = str[i];
}
}
string::string(const string& source)
//copy constructor
{
current_length = source.current_length;
allocated = current_length + 1;
sequence = new char[allocated];
for (size_t i = 0; i < allocated; i++) {
sequence[i] = source.sequence[i];
}
}
//~string();
// CONSTANT MEMBER FUNCTIONS for the string class:
// size_t length( ) const
// Postcondition: The return value is the number of characters in the
// string.
//
// char operator [ ](size_t position) const
// Precondition: position < length( ).
// Postcondition: The value returned is the character at the specified
// position of the string. A string's positions start from 0 at the start
// of the sequence and go up to length( )-1 at the right end.
char string::operator [ ](size_t position) const
{
assert(position < length());
return (sequence[position]);
}
// MODIFICATION MEMBER FUNCTIONS for the string class:
// void operator +=(const string& addend)
// Postcondition: addend has been catenated to the end of the string.
//
void string::operator =(const string& source)
{
//string assigned to self
if (sequence == source.sequence)
{
return;
}
if (source.current_length > this->allocated)
reserve(source.current_length);
delete[] sequence;
current_length = source.current_length;
allocated = current_length + 1;
for (size_t i = 0; i < allocated; i++) {
sequence[i] = source.sequence[i];
}
}
void string::operator +=(const string& addend)
{
if (this->current_length + addend.current_length > this->allocated)
{
reserve(current_length + addend.allocated);
}
//copy addend to sequence
for (size_t i = 0; i < addend.current_length; i++)
{
sequence[i + current_length] = addend.sequence[i];
}
current_length = current_length + addend.current_length;
}
// void operator +=(const char addend[ ])
// Precondition: addend is an ordinary null-terminated string.
// Postcondition: addend has been catenated to the end of the string.
void string::operator +=(const char addend[])
{
if (this->current_length + strlen(addend) > this->allocated)
reserve(current_length + strlen(addend));
//copy addend to sequence
for (size_t i = 0; i < strlen(addend); i++)
{
sequence[i + current_length] = addend[i];
}
current_length += strlen(addend);
}
// void operator +=(char addend)
// Postcondition: The single character addend has been catenated to the
// end of the string.
//
void string::operator +=(char addend)
{
if ((this->current_length + 1) > (this->allocated))
{
reserve(allocated + 1);
}
//copy addend to sequence
sequence[current_length] = addend;
current_length += 1;
}
// void reserve(size_t n)
// Postcondition: All functions will now work efficiently (without
// allocating new memory) until n characters are in the string.
void string::reserve(size_t n)
{
assert(n > current_length);
//create new array
char *newSequence = new char[n];
if (n == allocated)
{
return;
}
if (n < current_length + 1)
{
n = current_length + 1;
}
for (size_t i = 0; i < current_length; i++)
{
newSequence[i] = sequence[i];
}
delete[] sequence;
//update capacity
allocated = n;
//point data at new array
sequence = newSequence;
}
//Friend Functions
bool operator ==(const string& s1, const string& s2)
{
return (s1 == s2);
}
bool operator !=(const string& s1, const string& s2)
{
return !(s1 == s2); //(strcmp(s1.sequence, s2.sequence) == 0);
}
bool operator >=(const string& s1, const string& s2)
{
return (s1 >= s2); //(strcmp(s1.sequence, s2.sequence) >= 0);
}
bool operator <=(const string& s1, const string& s2)
{
return (s1 <= s2); //(strcmp(s1.sequence, s2.sequence) <= 0);
}
bool operator > (const string& s1, const string& s2)
{
return (s1 > s2); //(strcmp(s1.sequence, s2.sequence) > 0);
}
bool operator < (const string& s1, const string& s2)
{
return (s1 < s2); // (strcmp(s1.sequence, s2.sequence) < 0);
}
// NON-MEMBER FUNCTIONS for the string class
// string operator +(const string& s1, const string& s2)
// Postcondition: The string returned is the catenation of s1 and s2.
//
string operator +(const string& s1, const string& s2)
{
string temp = s1;
temp = s1 + s2;
return temp;
}
// istream& operator >>(istream& ins, string& target)
// Postcondition: A string has been read from the istream ins, and the
// istream ins is then returned by the function. The reading operation
// skips white space (i.e., blanks, newlines, tabs) at the start of ins.
// Then the string is read up to the next white space or the end of the
// file. The white space character that terminates the string has not
// been read.
//
istream& operator >>(istream& ins, string& target)
{
char newInput;
while (ins && isspace(ins.peek()))
ins.ignore();
target = ("");
while (ins && !isspace(ins.peek())) //(ins.peek())))
{
ins >> newInput;
cout << newInput;
target.operator+=(newInput);
}
return ins;
}
// ostream& operator <<(ostream& outs, const string& source)
// Postcondition: The sequence of characters in source has been written
// to outs. The return value is the ostream outs.
ostream& operator <<(ostream& outs, const string& source)
{
outs << source.sequence;
return outs;
}
//
// void getline(istream& ins, string& target, char delimiter)
void getline(istream& ins, string& target, char delimiter)
{
{
int count = 0;
char newLine;
while (ins)
{
ins.get(newLine);
target.operator+=(newLine);
}
}
}
}
#endif
#pragma once
The new[] and delete[] must be balanced.
The string::operator=(const string&) routine is delete[] the sequence array, which later gets delete[] again in the reserve routine.
while (ins && !isspace(ins.peek())) //(ins.peek())))
{
ins >> newInput;
target.operator+=(newInput);
}
Here you:
Check whether the stream has had any errors or attempted to read past the end
Extract the next character, assume this succeeded, then see whether it's a space
Read said character, and again assume this succeeded — if it did, it is assigned to newInput
Insert the contents of newInput to target (with a direct function call for some reason)
If the next read fails, you have no checking of that, and newInput isn't what you think it is.
You've only checked for errors before doing a thing.
Perhaps something like this would better suit:
while (true) {
const auto next = ins.peek();
if (!ins) break;
if (isspace(next)) break;
ins >> newInput;
target += newInput;
}
I'm assuming that if the peek succeeded then the >> will also, but in practice I'd probably put another check for !ins before the target += line, unless I were concerned about speed. In particular, you should double-check whether peek() sets eofbit, because I can't remember and, if it doesn't, you'll definitely need another if.
Related
I realized string class MyString. Here is code:
#include <iostream>
#include <cstring>
using std::cout;
using std::endl;
class MyString{
private:
char * content;
int length;
void copy(const MyString & source);
public:
MyString();
MyString(const char * source);
~MyString();
MyString(const MyString & source);
void print(void);
MyString & operator = (const MyString &source);
friend std::ostream & operator << (std::ostream & out, const MyString& towrite);
friend std::istream & operator >> (std::istream & in, MyString & toread);
};
MyString::MyString(){
content = new char[1];
content[0] = '\0';
length = 0;
}
MyString::MyString(const char *source){
length = strlen(source);
content = new char[length + 1];
strcpy(content, source);
}
MyString::~MyString(){
delete[] content;
}
void MyString::copy(const MyString & source){
length = source.length;
content = new char[length + 1];
strcpy(content, source.content);
}
MyString::MyString(const MyString & source){
copy(source);
}
void MyString::print(void){
cout << "" << content << endl;
}
MyString &MyString::operator=(const MyString &source){
copy(source);
return *this;
}
std::ostream & operator<<(std::ostream & out,const MyString& towrite){
out << towrite.content;
return out;
}
std::istream & operator >> (std::istream & in, MyString & toread){
int length;
std::cout << "Enter length of word: " << endl;
std::cin >> length;
toread.length = length;
toread.content = new char[toread.length+1];
for (int i = 0; i < toread.length; i++){
in >> toread.content[i] ;
}
toread.content[toread.length] = '\0';
return in;
}
My question is related to overloaded operator >>.
For this main program:
int main(){
MyString word;
std::cout<<"Enter some word: "<<endl;
std::cin>>word;
std::cout<<"Your entered: "<<word<<endl;
}
this is output:
Enter some word:
Enter length of word:
5
stack
Your entered: stack
Process returned 0 (0x0) execution time : 8.313 s
Press any key to continue.
It prints correctly string user entered, but it doesn't "mimic" original string class on the way I want. Here is why.
In case of using C++ string class:
int main(){
std::string word;
std::cout<<"Enter some word: "<<endl;
std::cin>>word;
std::cout<<"Your entered: "<<word<<endl;
}
user doesn't need to enter length of word. Can I achieve this with my class?
EDIT1:
I did it on this way:
std::istream & operator >> (std::istream & in, MyString & toread){
char *temp;
temp = new char[100];
char c;
int i = 0;
while(c != '\n'){
c = getchar();
temp[i++] = c;
}
temp[i] = '\0';
int length = i-1;
toread.length = length;
toread.content = new char[toread.length+1];
for(int i = 0 ; i < toread.length ; i++){
toread.content[i] = temp[i];
}
delete [] temp;
toread.content[toread.length+1]='\0';
}
It works as it should. However, I get warning because I didn't return "in":
||=== Build: Debug in fdsfsdf (compiler: GNU GCC Compiler) ===|
C:\Users\hae\Desktop\fdsfsdf\main.cpp||In function 'std::istream& operator>>(std::istream&, MyString&)':|
C:\Users\hae\Desktop\fdsfsdf\main.cpp|137|warning: no return statement in function returning non-void [-Wreturn-type]|
||=== Build finished: 0 error(s), 1 warning(s) (0 minute(s), 4 second(s)) ===|
||=== Run: Debug in fdsfsdf (compiler: GNU GCC Compiler) ===|
Here's a stripped down version of a similar class I wrote a long time ago. It's an antique, but it should work, and solves some of the issues with your class.
class charray {
public:
charray();
~charray();
charray(const charray&);
charray(const char*);
charray& operator=(const charray&);
charray& operator=(const char*);
void swap(charray&);
const char* c_str() const
{ return m_elem; }
unsigned int size() const
{ return m_size; }
private:
void m_resize(unsigned int size);
char* m_elem;
unsigned int m_size;
};
// private.
void charray::m_resize(unsigned int size)
{
char* elem = new char[size+1];
memcpy(elem, m_elem, std::min(m_size, size));
elem[size] = '\0';
delete [] m_elem;
m_elem = elem;
m_size = size;
}
// public.
charray::charray()
: m_elem(0), m_size(0)
{
m_resize(0);
}
charray::~charray()
{
delete [] m_elem;
}
charray::charray(const charray& src)
: m_elem(0), m_size(0)
{
unsigned int size = src.size();
m_resize(size);
memcpy(m_elem, src.c_str(), size);
}
charray::charray(const char* src)
: m_elem(0), m_size(0)
{
unsigned int size = std::strlen(src);
m_resize(size);
memcpy(m_elem, src, size);
}
charray& charray::operator=(const charray& rhs)
{
charray temp(rhs);
this->swap(temp);
return *this;
}
charray& charray::operator=(const char* rhs)
{
charray temp(rhs);
this->swap(temp);
return *this;
}
void charray::swap(charray& b)
{
std::swap(m_elem, b.m_elem);
std::swap(m_size, b.m_size);
}
Here is what you're probably most interested in. Pay close attention to the details. When dealing with memory directly, the difference between a working implementation and a broken one is often very subtle.
Note: The operators are not friends. They do not access private data.
std::ostream& operator<<(std::ostream& out, const charray& in)
{
return out << in.c_str();
}
std::istream& operator>>(std::istream& in, charray& out)
{
// verify no errors are set, flush tied streams, strip leading
// whitespace.
std::istream::sentry sentry(in);
if (!sentry)
return in;
unsigned int size = 0;
unsigned int tail = 0;
char* temp = 0;
int next; // #note int not char (to record EOF).
while ((next = in.get()) != in.eof() && !std::isspace(next)) {
// if temp buffer is exhausted, then double the buffer size.
// (base size of 16).
if (tail == size) {
unsigned int newsize = std::max(2*size, 16u);
char* newtemp = new char[newsize+1];
memcpy(newtemp, temp, size);
delete [] temp;
temp = newtemp;
size = newsize;
}
temp[tail++] = next;
}
// #note because the stream is prepeared with istream::sentry, there
// will be at least one non-whitespace character in the stream.
assert(temp != 0);
temp[tail] = '\0';
out = temp;
delete [] temp;
return in;
}
A much easier and safer way to do the exact same thing,
#include <vector>
std::istream& operator>>(std::istream& in, charray& out)
{
std::istream::sentry sentry(in);
if (!sentry)
return in;
std::vector<char> temp;
int next;
while ((next = in.get()) != in.eof() && !std::isspace(next))
temp.push_back(next);
temp.push_back('\0');
out = &temp[0];
return in;
}
Edit
The above is outmoded (pre C++11). A modern implementation would likely handle construction and assignment differently. Here are updated versions of those methods,
Note: The method m_resize is gone. Everything is handled through constructors.
charray::charray(const char* src, unsigned int size)
: m_elem{ new char[size+1]{} }, m_size{ size }
{
std::copy(src, src + size, m_elem);
}
charray::charray()
: charray(nullptr, 0)
{}
charray::charray(const charray& src)
: charray(src.m_elem, src.m_size)
{}
charray::charray(const char* src)
: charray(src, std::strlen(src))
{}
charray::charray(charray&& src)
: m_elem{ src.m_elem }, m_size{ src.m_size }
{
src.m_elem = nullptr;
src.m_size = 0;
}
// handle both move and copy assignment.
charray& charray::operator=(charray rhs)
{
this->swap(rhs);
return *this;
}
Hope this helps. Good luck.
I have a problem with operator>> when I try to use it in my class String. I need to make a string from keyboard, but all my tries make fails. Help me, please.
When I try to turn in this code, I always have a crash.
#include<iostream>
#include<fstream>
using namespace std;
class myString
{
public:
friend std::ostream& operator<< (std::ostream& out, const myString& other);
friend std::istream& operator>> (std::istream& in, myString& other);
myString()
{
str = nullptr;
length = 0;
}
myString(const char* str)
{
length = strlen(str);
this->str = new char[length + 1];
for (int i = 0; i < length; i++)
{
this->str[i] = str[i];
}
this->str[length] = '\0';
}
~myString()
{
delete[] this->str;
}
myString(const myString& other)
{
length = strlen(other.str);
this->str = new char[length + 1];
for (int i = 0; i < length; i++)
{
this->str[i] = other.str[i];
}
this->str[length] = '\0';
}
myString& operator =(const myString& other)
{
if (this->str != nullptr)
{
delete[] str;
}
length = strlen(other.str);
this->str = new char[length + 1];
for (int i = 0; i < length; i++)
{
this->str[i] = other.str[i];
}
this->str[length] = '\0';
return *this;
}
myString& operator =(const char* other)
{
if (this->str != nullptr)
{
delete[] str;
}
length = strlen(other);
this->str = new char[length + 1];
for (int i = 0; i < length; i++)
{
this->str[i] = other[i];
}
this->str[length] = '\0';
return *this;
}
myString& operator +=(myString const& other) {
return (this->operator=(this->operator+(other)));
}
myString operator +(const myString& other)
{
myString newStr;
int thisLength = strlen(this->str);
int otherLength = strlen(other.str);
newStr.length = thisLength + otherLength;
newStr.str = new char[thisLength + otherLength + 1];
int i = 0;
for (; i < thisLength; i++)
{
newStr.str[i] = this->str[i];
}
for (int j = 0; j < otherLength; j++, i++)
{
newStr.str[i] = other.str[j];
}
newStr.str[thisLength + otherLength] = '\0';
return newStr;
}
void Print()
{
cout << str;
}
int Length()
{
return length;
}
bool operator ==(const myString& other)
{
if (this->length != other.length)
{
return false;
}
for (int i = 0; i < this->length; i++)
{
if (this->str[i] != other.str[i])
{
return false;
}
}
return true;
}
bool operator !=(const myString& other)
{
return !(this->operator==(other));
}
char& operator [](int index)
{
return this->str[index];
}
private:
char* str;
int length;
};
ostream& operator<< (ostream& out, const myString& other)
{
out << other.str;
return out;
}
istream& operator >> (istream& in, myString& other)
{
in.getline(other.str, sizeof(other.str));
return in;
}
int main()
{
myString str_3;
cin >> str_3;
cout << str_3;
return 0;
}
sizeof(other.str) is not the size of allocated buffer but the size of the pointer.
other.str is initialized to nullptr in the constructor, so it will try to read into invalid place and it will lead to Segmentation Fault.
Changing the constructor to
myString()
{
str = new char[1];
length = 0;
}
to keep the buffer size always length + 1 and changing the operator>> to
istream& operator >> (istream& in, myString& other)
{
in.getline(other.str, other.length + 1);
return in;
}
will prevent it from getting Segmentation Fault.
This won't solve the problem that the reading will be limited to length of already assigned string.
Improving the behavior will require other modifications like reading characters one-by-one and allocating buffer according to the size read.
You are trying to read to a pointer initialized with nullptr and you use sizeof() of that pointer when you have length data member. Since you already defined assignment operator for char array you can just use it:
istream& operator >> (istream& in, myString& other)
{
char buffer[256];
in.getline(buffer, sizeof(buffer));
other = buffer;
return in;
}
note buffer size is arbitrary here, real application should handle different sizes and grow on need, but that would require more advanced string implementation than yours. For your simplified solution which looks like student task this could be fine.
Note: your operator<< also has issue, if you call it on default constructed object it would lead to UB, as std::ostream does not accept nullptr on const char *. Simple check for nullptr would be sufficient there:
ostream& operator<< (ostream& out, const myString& other)
{
if(other.str)
out << other.str;
return out;
}
Ironically you did check for nullptr for delete[] which is not necessary.
You do not allocate space for your data member str in the default constructor. So when you write
myString str_3;
cin >> str_3;
then your code in operator>> (i.e. in.getline(other.str, sizeof(other.str));) will write to memory that you did not allocate before).
Make sure that str provides enough allocated memory before writing to it, e.g. by using alloc or realloc.
I am working on building a string class in C++. Currently I am trying to override the subscript operator so users can get and modify individual characters.
#ifndef STRING_HPP
#define STRING_HPP
#include "test.hpp"
#include <cstring>
#include <iosfwd>
struct String
{
// Defines the npos value.
static constexpr std::size_t npos = -1;
int len;
char *str;
String()
:len(0), str(0){}
String(char const * S)
:len(strlen(S)), str(new char[len + 1]){
assert(S != 0);
strcpy(str, S);
}
~String(){
delete[]str;
}
String (char *S, std::size_t const n)
:len(n), str(new char[len + 1]){
assert(S != 0);
assert(strlen(S) >= n);
strncpy(str, S, n);
str += '\0';
}
String operator +=(String const &S){
int n = len + S.len;
char * p = new char[n+1];
strcpy(p + len, S.str);
len = n;
str = p;
return *this;
}
char* data() const {
return this->str;
}
bool empty() const {
return (this->len == 0);
}
size_t size()const {
size_t temp = len;
return temp;
}
//assignment operator
String operator =(String const &s){
String temp(s);
swap(temp);
return *this;
}
void swap(String &s){
std::swap(len, s.len);
std::swap(str, s.str);
}
size_t find(const char c){
char * p = strchr(this->str, c);
if(p){
return (str - p);
}else{
return npos;
}
}
char &operator[](const size_t pos){
assert(pos >= 0);
assert(pos < this->size());
return str[pos];
//return output;
}
String substr(int index, int dist){
String output((this->str + index) ,dist);
return output;
}
};
// Output
std::ostream& operator<<(std::ostream&, String const&);
//String operator +=(String const &);
bool operator <(String const &, String const &);
bool operator >(String const &, String const &);
bool operator <=(String const &, String const &);
bool operator >=(String const &, String const &);
bool operator ==(String const &, String const &);
#endif
The portion of main that calls the subscript function is:
String s1 = "String";
s1[0] = 'a';
The error I am getting is:
error: passing 'const String' as 'this' argument of 'char& String::operator[](size_t)' discards qualifiers [-fpermissive]
Thanks!
Edit
Updated error message to be correct
turns out the answer is just to add a 'const' at the end of the function:
char &operator[](const size_t pos)const{
assert(pos >= 0);
assert(pos < this->size());
return str[pos];
//return output;
}
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 }.
I realized string class MyString. Here is code:
#include <iostream>
#include <cstring>
using std::cout;
using std::endl;
class MyString{
private:
char * content;
int length;
void copy(const MyString & source);
public:
MyString();
MyString(const char * source);
~MyString();
MyString(const MyString & source);
void print(void);
MyString & operator = (const MyString &source);
friend std::ostream & operator << (std::ostream & out, const MyString& towrite);
friend std::istream & operator >> (std::istream & in, MyString & toread);
};
MyString::MyString(){
content = new char[1];
content[0] = '\0';
length = 0;
}
MyString::MyString(const char *source){
length = strlen(source);
content = new char[length + 1];
strcpy(content, source);
}
MyString::~MyString(){
delete[] content;
}
void MyString::copy(const MyString & source){
length = source.length;
content = new char[length + 1];
strcpy(content, source.content);
}
MyString::MyString(const MyString & source){
copy(source);
}
void MyString::print(void){
cout << "" << content << endl;
}
MyString &MyString::operator=(const MyString &source){
copy(source);
return *this;
}
std::ostream & operator<<(std::ostream & out,const MyString& towrite){
out << towrite.content;
return out;
}
std::istream & operator >> (std::istream & in, MyString & toread){
int length;
std::cout << "Enter length of word: " << endl;
std::cin >> length;
toread.length = length;
toread.content = new char[toread.length+1];
for (int i = 0; i < toread.length; i++){
in >> toread.content[i] ;
}
toread.content[toread.length] = '\0';
return in;
}
My question is related to overloaded operator >>.
For this main program:
int main(){
MyString word;
std::cout<<"Enter some word: "<<endl;
std::cin>>word;
std::cout<<"Your entered: "<<word<<endl;
}
this is output:
Enter some word:
Enter length of word:
5
stack
Your entered: stack
Process returned 0 (0x0) execution time : 8.313 s
Press any key to continue.
It prints correctly string user entered, but it doesn't "mimic" original string class on the way I want. Here is why.
In case of using C++ string class:
int main(){
std::string word;
std::cout<<"Enter some word: "<<endl;
std::cin>>word;
std::cout<<"Your entered: "<<word<<endl;
}
user doesn't need to enter length of word. Can I achieve this with my class?
EDIT1:
I did it on this way:
std::istream & operator >> (std::istream & in, MyString & toread){
char *temp;
temp = new char[100];
char c;
int i = 0;
while(c != '\n'){
c = getchar();
temp[i++] = c;
}
temp[i] = '\0';
int length = i-1;
toread.length = length;
toread.content = new char[toread.length+1];
for(int i = 0 ; i < toread.length ; i++){
toread.content[i] = temp[i];
}
delete [] temp;
toread.content[toread.length+1]='\0';
}
It works as it should. However, I get warning because I didn't return "in":
||=== Build: Debug in fdsfsdf (compiler: GNU GCC Compiler) ===|
C:\Users\hae\Desktop\fdsfsdf\main.cpp||In function 'std::istream& operator>>(std::istream&, MyString&)':|
C:\Users\hae\Desktop\fdsfsdf\main.cpp|137|warning: no return statement in function returning non-void [-Wreturn-type]|
||=== Build finished: 0 error(s), 1 warning(s) (0 minute(s), 4 second(s)) ===|
||=== Run: Debug in fdsfsdf (compiler: GNU GCC Compiler) ===|
Here's a stripped down version of a similar class I wrote a long time ago. It's an antique, but it should work, and solves some of the issues with your class.
class charray {
public:
charray();
~charray();
charray(const charray&);
charray(const char*);
charray& operator=(const charray&);
charray& operator=(const char*);
void swap(charray&);
const char* c_str() const
{ return m_elem; }
unsigned int size() const
{ return m_size; }
private:
void m_resize(unsigned int size);
char* m_elem;
unsigned int m_size;
};
// private.
void charray::m_resize(unsigned int size)
{
char* elem = new char[size+1];
memcpy(elem, m_elem, std::min(m_size, size));
elem[size] = '\0';
delete [] m_elem;
m_elem = elem;
m_size = size;
}
// public.
charray::charray()
: m_elem(0), m_size(0)
{
m_resize(0);
}
charray::~charray()
{
delete [] m_elem;
}
charray::charray(const charray& src)
: m_elem(0), m_size(0)
{
unsigned int size = src.size();
m_resize(size);
memcpy(m_elem, src.c_str(), size);
}
charray::charray(const char* src)
: m_elem(0), m_size(0)
{
unsigned int size = std::strlen(src);
m_resize(size);
memcpy(m_elem, src, size);
}
charray& charray::operator=(const charray& rhs)
{
charray temp(rhs);
this->swap(temp);
return *this;
}
charray& charray::operator=(const char* rhs)
{
charray temp(rhs);
this->swap(temp);
return *this;
}
void charray::swap(charray& b)
{
std::swap(m_elem, b.m_elem);
std::swap(m_size, b.m_size);
}
Here is what you're probably most interested in. Pay close attention to the details. When dealing with memory directly, the difference between a working implementation and a broken one is often very subtle.
Note: The operators are not friends. They do not access private data.
std::ostream& operator<<(std::ostream& out, const charray& in)
{
return out << in.c_str();
}
std::istream& operator>>(std::istream& in, charray& out)
{
// verify no errors are set, flush tied streams, strip leading
// whitespace.
std::istream::sentry sentry(in);
if (!sentry)
return in;
unsigned int size = 0;
unsigned int tail = 0;
char* temp = 0;
int next; // #note int not char (to record EOF).
while ((next = in.get()) != in.eof() && !std::isspace(next)) {
// if temp buffer is exhausted, then double the buffer size.
// (base size of 16).
if (tail == size) {
unsigned int newsize = std::max(2*size, 16u);
char* newtemp = new char[newsize+1];
memcpy(newtemp, temp, size);
delete [] temp;
temp = newtemp;
size = newsize;
}
temp[tail++] = next;
}
// #note because the stream is prepeared with istream::sentry, there
// will be at least one non-whitespace character in the stream.
assert(temp != 0);
temp[tail] = '\0';
out = temp;
delete [] temp;
return in;
}
A much easier and safer way to do the exact same thing,
#include <vector>
std::istream& operator>>(std::istream& in, charray& out)
{
std::istream::sentry sentry(in);
if (!sentry)
return in;
std::vector<char> temp;
int next;
while ((next = in.get()) != in.eof() && !std::isspace(next))
temp.push_back(next);
temp.push_back('\0');
out = &temp[0];
return in;
}
Edit
The above is outmoded (pre C++11). A modern implementation would likely handle construction and assignment differently. Here are updated versions of those methods,
Note: The method m_resize is gone. Everything is handled through constructors.
charray::charray(const char* src, unsigned int size)
: m_elem{ new char[size+1]{} }, m_size{ size }
{
std::copy(src, src + size, m_elem);
}
charray::charray()
: charray(nullptr, 0)
{}
charray::charray(const charray& src)
: charray(src.m_elem, src.m_size)
{}
charray::charray(const char* src)
: charray(src, std::strlen(src))
{}
charray::charray(charray&& src)
: m_elem{ src.m_elem }, m_size{ src.m_size }
{
src.m_elem = nullptr;
src.m_size = 0;
}
// handle both move and copy assignment.
charray& charray::operator=(charray rhs)
{
this->swap(rhs);
return *this;
}
Hope this helps. Good luck.