Home > database >  Concatenate 2 string using operator = in class C
Concatenate 2 string using operator = in class C

Time:06-05

I've seen some similar questions before asking, but I'm still stuck at the part of concatenating two strings using operator =.

Currently, I can get separate strings correctly by constructor method. But when I compile code, the line str[length i] = s[i]; in the method String& String::operator = (const String& s) shows an error:

no match for ‘operator[]’ (operand types are ‘const String’ and ‘unsigned int’)

So I need your help to fix this bug.

Here's my code:

#include <iostream>
#include <cstring>
 
class String {
 
    // Initialise char array
    char* data;
    unsigned length;
 
public:
    // Constructor without arguments 
    String();
 
    // Constructor with 1 arguments
    String(char* s);
 
    // Copy Constructor
    String(const String& source);
 
    // Move Constructor
    String(String&& source);
 
    // Destructor
    ~String() { delete[] data; }
    
    /*! 
     *  @brief String length.
     *  @return Value in String @c length.
     */
    unsigned len ( ) const;
    
    /*! 
     *  @brief Append to String.
     *  @param[in] s A String object.
     *  @return A String reference to *this.
     *  @post String will equal the concatenation of itself with @a s.
     */
    String& operator = (const String& s);
};
 
// Constructor with no arguments
String::String()
    : data{ nullptr }
{
    data = new char[1];
    data[0] = '\0';
}
 
// Constructor with one arguments
String::String(char* s)
{
    if (s == nullptr) {
        data = new char[1];
        data[0] = '\0';
    }
 
    else {
 
        data = new char[strlen(s)   1];
 
        // Copy character of s[]
        // using strcpy
        strcpy(data, s);
        data[strlen(s)] = '\0';
 
        std::cout << data << "\n";
    }
}
 
// Copy Constructor
String::String(const String& source)
{
    data = new char[strlen(source.data)   1];
    strcpy(data, source.data);
    data[strlen(source.data)] = '\0';
}
 
// Move Constructor
String::String(String&& source)
{
    data = source.data;
    source.data = nullptr;
}

unsigned String::len ( ) const 
{
    return length;
}

String& String::operator = (const String& s) 
{
    unsigned len = length   s.len();
    char*    str = new char[len];

    for (unsigned j=0; j < length; j  )
        str[j] = data[j];

    for (unsigned i=0; i < s.len(); i  )
        str[length i] = s[i];

    delete data;
    length = len;
    data   = str;
    return *this;    
}
 
int main()
{
    // Constructor with no arguments
    String a;
 
    // Convert string literal to
    // char array
    char temp[] = "Hello world.";
 
    // Constructor with one argument
    std::cout << "s1: ";
    String s1{ temp };
 
    // Copy constructor
    String s11{ a };
 
    char temp1[] = "Goodbye!";
    std::cout << "s2: ";
    String s2{ temp1 };
    
    String s3 = String s1   String s2;

    return 0;
}

Another way of writing main function:

int main()
{
String s1("Hello World.");
String s2("Goodbye!");
std::cout << "s1: " << s1 << std::endl;
std::cout << "s2: " << s2 << std::endl;
String s3 = s1   s2;
std::cout << "s3: " << s3 << std::endl;
std::cout << "The last char of s3: " << s3[s3.size()-1] << std::endl;
return 0;
}

Expected result:

s1: Hello World.
s2: Goodbye!
s3: Hello World.Goodbye!
The last char of s3: !

How can I modify my code to get s3 and last char of s3 correctly?

CodePudding user response:

In many of your constructors, you do not set length which leaves it with an indeterminate value - and reading such values makes the program have undefined behavior. So, first fix that:

#include <algorithm> // std::copy

// Constructor with no arguments
String::String() : data{new char[1]{'\0'}}, length{0} {}

// Constructor with one argument
String::String(const char* s) {     // note: const char*
    if (s == nullptr) {
        data = new char[1]{'\0'};
        length = 0;
    } else {
        length = std::strlen(s);
        data = new char[length   1];
        std::copy(s, s   length   1, data);
    }
}

// Copy Constructor
String::String(const String& source) : data{new char[source.length   1]},
                                       length{source.length}
{
    std::copy(source.data, source.data   length   1, data);
}

// Move Constructor
String::String(String&& source) : String() {
    std::swap(data, source.data);
    std::swap(length, source.length);
}

In operator = you are trying to use the subscript operator, String::operator[], but you haven't added such an operator so instead of s[i], use s.data[i]:

String& String::operator =(const String& s) {
    unsigned len = length   s.length;
    char* str = new char[len   1];
    for (unsigned j = 0; j < length; j  ) str[j] = data[j];
    for (unsigned i = 0; i < s.length; i  ) str[length   i] = s.data[i];
    str[len] = '\0';
    delete[] data;        // note: delete[] - not delete
    length = len;
    data = str;
    return *this;
}

And for String s3 = s1 s2; to work, you need a free operator overload:

String operator (const String& lhs, const String& rhs) {
    String rv(lhs);
    rv  = rhs;
    return rv;
}

CodePudding user response:

For starters neither constructor sets the data member length. So the operator

String& String::operator = (const String& s) 
{
    unsigned len = length   s.len();
    char*    str = new char[len];
    //...

has undefined behavior.

Also provided that the data member length was initialized you need to write

    char*    str = new char[len   1];

instead of

    char*    str = new char[len];

to reserve memory for the terminating zero character '\0' because you are using the standard C string function strcpy in the copy constructor

strcpy(data, source.data);

And the class does not have the subscript operator used in this for loo[

for (unsigned i=0; i < s.len(); i  )
    str[length i] = s[i];

And you forgot to append the terminating zero character '\0'.

Pay attention to that there is no member function size in the class used in this expression

s3[s3.size()-1]

And this construction

String s3 = String s1   String s2;

is invalid. At least you should write

String s3 = s1 s2;

and correspondingly define the operator .

  • Related