C style strings and operator overloading in C++ [duplicate] - c++

This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 7 years ago.
I tried to overload the + operator on my own C styled version of string class.
Everything is fine except for the display() call for the second string s2 which displays garbage values.
class string_ {
char *str;
int len;
public :
...
void display()
{
cout << str;
}
};
string_ :: string_()
{
str = 0;
len = 0;
}
string_ :: ~string_()
{
delete []str;
len = 0;
}
string_ :: string_(char *s,int l)
{
len = l + 1; // +1 for \0
str = new char[len];
int i;
for(i=0;i<len;i++)
str[i] = s[i];
str[i] = '\0';
}
string_ string_ :: operator +(string_ c)
{
int j = 0, i = 0;
string_ s;
s.len = len + c.len - 1;
s.str = new char[s.len];
while (str[i] != '\0')
{s.str[i] = str[i]; i++;}
while (c.str[j] != '\0')
{s.str[i] = c.str[j]; i++; j++; }
s.str[i] = '\0';
//The below statements gives the desired output
cout <<"\nIN operator +" << str;
cout <<"\nIN operator +" << c.str;
cout <<"\nIN operator +" << s.str;
return s;
}
int main()
{
char *str = "Hello";
char *str1 = " World";
string_ s1(str,5);
string_ s2(str1,6);
string_ s3 = s1 + s2;
cout << "\nstring s1 : ";
s1.display();
cout << "\nstring s2 : ";
s2.display(); //PROBLEM
cout << "\nConcatenated string : ";
s3.display();
return 0;
}

You are missing a proper copy-constructor where you clone the char-array from one string to another.
Also your operator+ should take a const-ref to your string class because a copy is not necessary here.
string_ string_ :: operator +(const string_& c)
The problem
Your 1st object has a pointer to a char-array, e.g. str=0x1. Because you have no copy-constructor the pointer-value is copied over automatically to the copy of your string. Two strings have now the same pointer. The first string deletes the array and the second will fail. Take a look at Rule of three which describes which functions should be implemented to avoid this problem. Edit: R Sahu was faster in the comments.
P.S. Since you use const-literals change char* to const char*.
P.S.2 Please post a MVCE next time.

Related

Member function of return type char* returns address that contains different string after while loop

My code reads input from a text file word by word and instantiates an object for each token. In the while loop, when I call get_value() on the VAR object and dereference it I get the string "foo" which is what I want, but outside of the loop I get the string belonging to the STRING object "HELLO". I'm pretty sure calling the constructor for STRING is what's causing the issue but I can't pin point the problem.
STRING and VAR have their own get_value()member function and they do not inherent from each other.
I even dynamically allocated memory in VAR's set_value() function so I'm pretty sure STRING() is not mutating anything. Excuse me if I posted too much.
Output
$ ./venom
0x7ffeeb3a02d8
foo
0x7ffeeb3a02f8
0x7ffeeb3a02d8
Hello
Hello
main.cpp
ifstream in("new.vnm");
string s;
STRING *ptr1;
VAR *ptr2;
while(in >> s){
if(s[0] == '"') {
//Address to (H)ello
STRING str(&s[1]);
ptr1 = &str;
//0x7ffeeb3a02f8 -- That's OK
cout << ptr1 << endl;
}
else if((s[0] > 'a' && s[0] < 'z') || (s[0] >'A' && s[0] < 'Z')) {
//Address to (f)oo
VAR var(&s[0]);
ptr2 = &var;
// 0x7ffeeb3a02d8 -- This is OK.
cout << ptr2 << endl;
// Value stored at ptr2 -- Prints foo -- That's OK.
for(int i = 0; ptr2->get_value()[i]; i ++)
cout << ptr2->get_value()[i];
cout << endl;
}
};
// 0x7ffeeb3a02d8 -- That's OK
cout << ptr2 << endl;
// Printing Value stored at ptr2 -- Hello -- This is NOT OK!
for(int i = 0; ptr2->get_value()[i]; i ++)
cout << ptr2->get_value()[i];
cout << endl;
// Printing Value stored at ptr1 -- That's OK.
for(int i = 0; ptr1->get_value()[i]; i ++)
cout << ptr1->get_value()[i];
cout << endl;
VAR.cpp
void VAR::set_name(char *name) {
this->name = new char[this->len+1];
for(int i = 0; i < len; i ++)
this->name[i] = name[i];
this->name[this->len+1] = '\0';
};
char *VAR::get_value() const {
return this->name;
};
STRING.cpp
char *STRING::get_value() const {
return this->value;
};
void STRING::set_value(char *str) {
this->value = new char[this->len + 1];
for(int i = 0; i < this->len; i ++)
this->value[i] = str[i];
this->value[this->len + 1] = '\0';
};
new.vnm (text file)
foo = "Hello";
ptr2->get_value() should point to foo not Hello.
Outside of the loop both ptr2 and ptr1 point to objects which no longer exist - they were already destroyed, because their scope was smaller. This is undefined behaviour and a serious error. In this case anything can happen and it's a lot of luck your program only prints not what you expect instead of just crashing.
You're taking a pointer to a locally scoped object, and then dereferencing that pointer after the object has gone out of scope. That's undefined behaviour.
Essentially your code is this
VAR *ptr2;
{
VAR var;
ptr2 = &var;
}
ptr2->get_value() // this is invalid because 'var' no longer exists.

Program to check if one string is contained cyclic in the other one

doing some exrecises for upcoming test. a bit stuck in this one.
"Write a program that asks the user for two strings and checks and prints a message if the second string is contained cyclic in the first string. The cyclic containment means that either the second string appears normally within the first string or the second string appears so that its prefix appears at the end of the first string and the continuation appears at the beginning of the first string".
You can assume that the strings contain only lowercase letters.
String functions are only allowed are : strlen, strcpy, strcmp, strcat
for example:
String A: itisaniceday
String B: sanic
Is a regular occurrence
String A: itisaniceday
String B: dayit
It's a cyclic occurence.
what I did so far:
#include <iostream>
#include <string.h>
using namespace std;
#define Max 128
int isCyclic(char* str1, char* str2);
int main()
{
char* str1 = new char[Max];
char* str2 = new char[Max];
cout << "Please enter two strings:" << endl;
cin >> str1 >> str2;
cout << isCyclic(str1, str2) << endl;
delete[] str1;
delete[] str2;
}
int isCyclic(char* str1, char* str2)
{
int s1 = strlen(str1);
int s2 = strlen(str2);
if (s1!=s2) // if string size is diffrent - they are not contained cyclic
{
return 0;
}
}
You will need two loops, first one over string 1 which is our starting point in string 1 for comparison and second one over string 2 which will be matched to string 1 in a cyclic way. If we reach the end of string 1 and still some characters are left in string 2 then cycle through string 1 starting from index 0.
#include <stdio.h>
#include <iostream>
#include <string.h>
// Should be avoided in general. Use scope resolution instead.
using namespace std;
char* isCyclic(char* s1, char* s2){
int s1_size = strlen(s1);
int s2_size = strlen(s2);
// s1 must contain s2
if(s2_size > s1_size)
return "No Occurence";
for(int i = 0; i < s1_size; i++){
int current = i;
// Boolean to track if we are currently cycling through s1
bool inCycle = false;
int j = 0;
for(; j < s2_size; j++, current++){
// character wise comparision
if(s2[j] != s1[current])
break;
if(! inCycle){
// start from first. Note that we are setting current = -1.
// as we will be incrementing it in the for loop.
if(current == s1_size - 1 && j < s2_size - 1){
current = -1;
inCycle = true;
}
}
}
if(j == s2_size){
if(inCycle)
return "cyclic";
else
return "regular";
}
}
return "No Occurence";
}
int main()
{
printf("Hello World\n");
char* s1 = "itisaniceday";
char* s2 = "dayitis";
cout<<"Occurence Type: "<<isCyclic(s1, s2)<<endl;
return 0;
}
Here is a solution for the second part of the problem (cyclic part). I simply go through all of the characters in the first string and checked if they are the beginning of a cyclic appearance of the second string.
To check that I used % (the modolu operation) if you don't know what it dose then you really need to learn it now.
Also I used bool instead of int because numbers are confusing (and cursed).
#include <iostream>
#include <string.h>
using namespace std;
#define Max 128
bool isCyclic(char* str1, char* str2);
bool isCyclic(char* str1, char* str2,int start);
int main()
{
char* str1 = new char[Max];
char* str2 = new char[Max];
cout << "Please enter two strings:" << endl;
cin >> str1 >> str2;
cout << isCyclic(str1, str2) << endl;
delete[] str1;
delete[] str2;
}
bool isCyclic(char* str1, char* str2) {
for(int i = 0; i < strlen(str1); i++) {
if(str1[i] == str2[0] && isCyclic(str1,str2,i)) {
return true;
}
}
return false;
}
bool isCyclic(char* str1, char* str2,int start)
{
int containingStrLen = strlen(str1);
for(int i = 0; i < strlen(str2); i++) {
if(str1[(start + i)%containingStrLen] != str2[i]) {
return false;
}
}
return true;
}
There are some things missing in this code still:
1) The first part of the problem (it can easily be derived from this code).
2) Some size validation such as making sure that str1 is bigger then str2 before using is cyclic. And that the strings are smaller then Max (I assume).
3) A proper result print.
Good luck in your exam :)
There's a simple trick : if you duplicate the string's prefix at its own end, the problem becomes a straight substring search as a cyclic match would be recomposed at the end. It also handles the corner case where the substring loops back on itself, such as "looploop" inside of "loop".
So here's how you'd do it in broken C-ish dialect:
bool containsCyclic(char const *string, char const *substring) {
std::size_t const stringLen = std::strlen(string);
std::size_t const substringLen = std::strlen(substring);
// Too long a substring wouldn't fit in the string
if(substringLen > 2 * stringLen)
return false;
// Concatenate `string` with its own substring-long prefix
char *const loopedString = new char[stringLen + substringLen + 1];
std::strcpy(loopedString, string);
{ // Partial reimplementation of std::strncpy(loopedString, string, substringLen)
char const *src = string;
char *dest = loopedString + stringLen;
for(std::size_t count = 0; count < substringLen; ++count)
*dest++ = *src++;
*dest = '\0';
}
{ // Partial and naïve reimplementation of std::strstr(loopedString, substring)
for(char const *start = loopedString; start < loopedString + stringLen; ++start) {
// Check if substring is present at this offset
char const *s1 = start;
char const *s2 = substring;
while(*s2 != '\0' && *s1 == *s2)
++s1, ++s2;
if(*s2 == '\0') {
// We found a complete match of substring inside loopedString
delete[] loopedString;
return true;
}
}
}
// No match found
delete[] loopedString;
return false;
}
And just for kicks, here it is in C++:
bool containsCyclicCpp(std::string const &string, std::string const &substring) {
std::string const loopedString = string + string.substr(0, substring.size());
return loopedString.find(substring) != std::string::npos;
}
See it live on Coliru (with tests!)

I really need help understanding how to write a class (declaration and definition) just by looking at a main program and sample execution output

I have an example that I've been looking over and I'm trying to figure out how to write the .h and .cpp files by looking at the main file and the output
I have a class called Flex:
#include <iostream>
#include "flex.h"
using namespace std;
int main()
{
Flex a, b("Merry"), c("Christmas");
cout << a << ',' << b << ',' << c << endl;
b.cat(a);
cout << b << endl;
b.cat(c);
cout << b << endl;
c.cat(c);
c.cat(c);
cout << c << endl;
return 0;
}
Execution output is:
* *,*Merry*,*Christmas*
*Merry *
*Merry Christmas*
*ChristmasChristmasChristmasChristmas*
And then, the declaration/definition files should look like this:
#include <iostream>
using namespace std;
class Flex
{
friend ostream& operator<< (ostream& s, const Flex& f);
public:
Flex(); // default constructor
Flex(const char *); // constructor with parameters
~Flex(); // destructor (not specifically required)
void cat(const Flex & f); // cat function -- concatenation
private:
char * str; // variable length string
int size;
};
and
#include <iostream>
#include <cstring>
#include "flex.h"
using namespace std;
ostream& operator<< (ostream& s, const Flex& f)
{
s << '*' << f.str << '*';
return s;
}
Flex::Flex()
{
size = 1; // size doesn't include null char
str = new char[size+1]; // allocate +1 for null char
strcpy(str," ");
}
Flex::Flex(const char * s)
{
size = strlen(s);
str = new char[size+1];
strcpy(str,s);
}
Flex::~Flex()
// not specifically required by the specs, but a good idea to have this
{
delete [] str;
}
void Flex::cat(const Flex & f)
// this function can also be made easier through the use of the
// strcat library function for concatenating strings.
// dyanamic reallocation still required, though.
{
int newsize = size + strlen(f.str);
char * temp = new char[newsize+1]; // allocate with room for '\0'
strcpy(temp,str); // copy this string to temp
for (int i = 0; i <= f.size; i++)
temp[size+i] = f.str[i]; // concatenate f.str to temp,
// including '\0'
delete [] str; // delete old array
str = temp; // set str to new one
size = newsize; // update size tracker
}
This question might be hard to explain, but how does one look at the main program and immediately knows what class he has to write?
I need to do this for a class that involves stats. I do not have a main program yet, but what would we be different since I wouldn't use chars anymore ?
How would I go about representing a stats class just by looking at a main file and output ?
Operator << sends '*' << f.str << '*'(Where f.str it`s your, Flex object, str value ) You have constructor of class Flex
Flex::Flex()
{
size = 1; // size doesn't include null char
str = new char[size+1]; // allocate +1 for null char
strcpy(str," ");
}
Flex::Flex(const char * s)
{
size = strlen(s);
str = new char[size+1];
strcpy(str,s);
}
When your initialize object like Flex a("Test"). Your a.str == "Test". When Flex a(), then a.str == "". Function cat is concatanation 2 value. If b.cat(a) it`s mean that b.str = b.str + a.str

C++ - implementation of string class

I'm trying to implement string class. Here is what I have done:
#include <iostream>
#include <cstring>
using namespace std;
class MyString{
private:
char * content;
int length;
public:
MyString ();
MyString ( const char * );
~MyString ();
MyString ( const MyString & );
void print ( void );
void operator = ( const MyString );
};
MyString :: MyString () {
content = 0;
length = 0;
}
MyString :: MyString(const char *n) {
length = strlen (n);
content = new char [ length ];
for ( int i = 0 ; i < length ; i++ ){
content [i] = n [i];
}
content [length] = '\0';
}
MyString :: ~ MyString () {
delete [] content;
content = 0;
}
MyString :: MyString ( const MyString & x ) {
length = x.length;
content = new char [length];
for( int i = 0 ; i < length ; i++ ){
content [i] = x.content [i];
}
content [length] = '\0';
}
void MyString :: print( void ) {
cout <<""<< content << endl;
}
void MyString :: operator = ( const MyString x ) {
length = x.length;
content = new char [length];
for( int i = 0 ; i < length ; i++ ){
content [i] = x.content [i];
}
content [length] = '\0';
}
int main() {
MyString word1 ("stackoverflow");
MyString word2;
word2 = word1;
word1.print();
word2.print();
}
I compiled it and this is what I get:
stackoverflow
stackoverflow
Process returned 0 (0x0) execution time : 0.050 s
Press any key to continue.
Although it looks correct according to result above, I wonder is it really correct? I'm not so familiar with C-style strings so I'm concerned
for example about line:
content [length] = '\0';
Since C-style strings has null terminator at end, I wanted to terminate my array but is this correct way to do it?
I used dynamic memory allocation and I also wonder did I free resources properly?
Are there some memory leaks?
Thanks in advance.
EDIT1:
I also overloaded opeartor + (I want to join "MyStrings"), here is code:
MyString MyString :: operator + ( const MyString & x ){
MyString temp;
temp.length = x.length + length;
temp.content = new char [ temp.length + 1 ];
int i = 0, j = 0;
while ( i < temp.length ) {
if (i < length ) {
temp.content [i] = content [i];
}
else {
temp.content [i] = x.content [j];
j ++;
}
i ++;
}
temp.content [ temp.length ] = '\0';
return temp;
}
Here is main program:
int main()
{
MyString word1 ( "stack" );
MyString word2 ( "overflow" );
MyString word3 = word1 + word2;
word3.print();
word3 = word2 + word1;
word3.print();
}
And here is result:
stackoverflow
overflowstack
Process returned 0 (0x0) execution time : 0.040 s
Press any key to continue.
I hope there are no problems with this code :)
EDIT2:
Here is implementation of + operator using for loops, instead of while:
MyString MyString :: operator + (const MyString & x){
MyString temp;
temp.length = x.length + length;
temp.content = new char [temp.length+1];
for( int i = 0 ; i < length ; i++ ){
temp.content[i] = content[i];
}
for( int i = length , j = 0 ; i <temp.length ; i++, j++){
temp.content[i] = x.content[j];
}
content[temp.length] = '\0';
return temp;
}
It's maybe better now because there is no if :)
You are trying to assign content[length] a value, but you haven't allocated enough memory for content[length] to be accessed. If length == 10, then you can access content[0] thru content[9], but not content[10].
This can be fixed of course by removing the line content[length] = \0 from both constructors, or if you want to append \0 you should increase the value of length by 1.
Have you considered just using std::string internally?
Edit: #Thane Plummer was first to point this out in the comments!
A few other notes and suggestions because there are are least two more gotchas waiting to leap out and strike.
#include <iostream>
#include <cstring>
// using namespace std; DANGER! namespace std is huge. Including all of it can
// have tragic, unforeseen consequences. Just use what you need.
using std::cout;
using std::endl;
class MyString
{
private:
char * content;
int length;
// will use clone to reduce duplication in the copy constructor and operator =
void copy(const MyString & source);
public:
MyString();
// it is nice to name the variables in the definition. The header may be the
// only documentation the user gets.
MyString(const char * source);
~MyString();
MyString(const MyString &source);
void print(void);
// changed prototype to match the expected format operator= format
MyString & operator =(const MyString &source);
//OP asked about this in a previous question.
friend std::ostream & operator<<(std::ostream & out,
const MyString& towrite);
};
MyString::MyString()
{
// content = 0;
//destructor needs something to delete[]. If content isn't set to something,
//you'll get a big ka-BOOM! when the MyString is destroyed
content = new char[1];
content[0] = '\0'; //this has the advantage of printing an empty MyString
// without crashing
length = 0;
}
MyString::MyString(const char *source) // Variable names should describe their purpose
{
//DANGER: strlen will fail horribly if passed an unterminated string. At a
// loss at the moment for a good, safe solution. Look into strnlen, but
// even it can't help you here.
length = strlen(source);
content = new char[length + 1]; //Needed one extra character to fit the NULL
/* If we got this far without dying, strcpy is no threat which makes this redundant:
for (int i = 0; i < length; i++)
{
content[i] = n[i];
}
content[length] = '\0';
*/
strcpy(content, source);
}
MyString::~MyString()
{
delete[] content;
// content = 0; string is gone. No need to clear this
}
void MyString::copy(const MyString & source)
{
length = source.length;
content = new char[length + 1];
// assuming that the source MyString is correctly formatted this is once again safe.
strcpy(content, source.content);
}
MyString::MyString(const MyString & source)
{
copy(source); // use the copy method
}
void MyString::print(void)
{
cout << "" << content << endl;
}
MyString &MyString::operator =(const MyString &source)
{
copy(source); // use the copy method again.
return *this; // allows chaining operations
}
std::ostream & operator<<(std::ostream & out,
const MyString& towrite)
{
out << towrite.content;
return out;
}
int main()
{
MyString word0;
MyString word1("stackoverflow");
MyString word2;
word2 = word1;
MyString word3(word2); //testing copy constructor
word1.print();
word2.print();
cout << word3 << endl; //testing outstream overload
// test output of empty string
word0.print();
cout << word0 << endl;
}
Edit:
Realized after posting that since we know the lengths of the strings, there are significant performance gains from using memcpy(content, source.content, length+1); in place of strcpy.
There are two errors. One has already been stated by Thane Plummer in the comments and by Tas in the answers:
MyString :: MyString(const char *n) {
length = strlen(n);
content = new char [length];
for( int i = 0 ; i < length ; i++ ){
content [i] = x.content [i];
}
content [length] = '\0';
}
if your string is the null terminated "abc\0", strlen will return 3 and not 4, so you'll only allocate 3 chars instead of 4 (edit: and to be complete, as previously stated, you indeed start to index from 0 and not 1, so content[length] will always overflow, even if you increase length)
The other error is less grave (and is actually legal but odd c++):
void operator = ( const MyString );
The copy assignment operator should take a const reference rather than a const value (otherwise you may uselessly call the copy constructor), and return a reference rather than void (so that you can chain some calls). The correct declaration is:
MyString& operator=(const MyString&);
The correct implementation is:
MyString& MyString::operator=(const MyString& x) {
length = x.length;
delete[] content;
content = new char [length];
for( int i = 0 ; i < length ; i++ ){
content [i] = x.content [i];
}
// actually not needed since x.content should already be null-terminated
// content[length - 1] = '\0';
return *this;
}

Segmentation fault error

`I am trying to write a program that reverses two strings, I though I had it done pretty well but when I run it, the program runs till line 26, then I get a segmentation fault error. The program compiles fine. I am wondering if there is a simple or obvious problem in my functions that I am not seeing, Any help would be appreciated!!
Thanks in advance
#include <iostream>
#include <string>
using namespace std;
// Reversing the characters in strings.
void reverse(string str);
void swap(char * first, char *last);
int main() {
// declarations and initialization
string str1;
string str2;
cout << "Please enter the first string of characters:\n";
cin >> str1;
cout << "Please enter the second string of characters:\n";
cin >> str2;
cout << "The strings before reversing are:" << endl;
cout << str1 << " " << str2 << endl;
// reverse str1
reverse(str1);
// reverse str2
reverse(str2);
// output
cout << "The strings after reversing: " << endl;
cout << str1 << " " << str2 << endl;
return 0;
}
void reverse(string str) {
int length = str.size();
char *first = NULL;
char *last = NULL;
first = &str[0];
last = &str[length - 1];
for (int i = 0; first < last; i++) {
swap(first, last);
first++;
last--;
}
}
void swap(char *first, char *last) {
char * temp;
*temp = *first;
*first = *last;
*last = *temp;
}
I don't know where line 26 is, but
char * temp;
*temp = ...
is not valid. temp should be pointed at a char, or (better yet) rewrite the function to where temp is a char.
Seth Carnegie observes that you'll have to pass the strings by reference if you want to modify the originals.
void reverse(string& str) { //pass by reference, so origional is modified
In your swap function, you are assigning a value to *temp when temp is not pointing to anything (it's uninitialized). Thus, your segmentation fault.
You want this:
void swap(char* first, char* last)
{
char temp = *first;
*first = *last;
*last = temp;
}
The other answers are valid in regards to the segfault cause.
I just think you may be interested in knowing that you can reverse a string easily using std::string's reverse_iterator:
std::string reverse(std::string str) {
std::string out;
for (std::string::reverse_iterator it = str.rbegin(); it != str.rend(); it++) {
out += *it;
}
return out;
}
So, calling:
reverse("foo");
...will return oof.
You're passing the strings by value, which means only a local copy of the string will be reversed in the reverse function. You should pass them by reference.
Also, don't alter the string's memory directly. Use operator[] like this:
for (size_t beg = 0, size_t end = str.size() - 1; beg < end; ++beg, --end)
str[beg] = str[end];
So all together:
void reverse(string& str); // prototype
....
void reverse(string& str) { // note the & which is pass by reference
int length = str.size();
for (size_t beg = 0, size_t end = str.size() - 1; beg < end; ++beg, --end)
str[beg] = str[end];
}
And as stated by Mooing Duck, the place you're probably crashing from is dereferencing a pointer which has a garbage value here:
char * temp;
*temp = ...
You're trying to assign some random memory a value, which is probably segfaulting you.
Again, others have pointed out the what the problem is and would like to show you this:
void reverse(std::string & str) {
for (int i = 0, last = str.size() - 1, lim = str.size() / 2 ; i < lim;) {
std::swap(str[i++], str[last--]);
}
}
I have not tested it thoroughly though.