c++stringclassheader-filescout

cout stops printing after one prompt inside method of class .cpp file


So I have a basic code: trying to define the string data type with the two functions, concatenation and printing it.

So what I did was declare a .cpp file and a .h file with the class contents and wrote a main.cpp to try and test my code but I am running into an unexpected error. Firstly, here are my main.cpp, stringConcat.h and stringConcat.cpp files -

main.cpp:

#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include "stringConcat.h"

using std::cin;
using std::cout;
using std::endl;
using std::initializer_list;
using std::string;
using std::vector;

int main()
{
    char input1[101], input2[101];
    cin.getline(input1, 101);
    cin.getline(input2, 101);

    String str1(input1);
    String str2(input2);
    String result = str1 + str2;

    result.display();

    return 0;
}

stringConcat.h:

class String
{
public:
    char *a;
    int length;
    String(char b[], int size=101)
    {
        a = &b[0];
        length = size;
    }
    String operator+(const String &other);
    void display();
};

stringConcat.cpp:

#include <iostream>
#include "stringConcat.h"
using namespace std;
String String::operator+(const String &other)
{
    int total = length + other.length;
    char temp[total];
    int counter = 0;
    for(int i = 0; i < length; i++)
    {
        if(*(a+i) == '\0')
            break;
        temp[counter++] = *(a+i);
    }
    temp[counter++] = ' ';
    for(int i = 0; i < other.length; i++)
    {
        if(*(other.a+i) == '\0')
            break;
        temp[counter++] = *(other.a+i);
    }
    temp[counter++] = '\0';
    return String(temp, counter);
}
void String::display()
{
    for(int i = 0; i < length; i++)
    {
        if(*(a+i) == '\0')
            break;
        cout<<*(a+i);
    }
    cout<<endl;
}

So what I am trying to do is intialise a string with a char pointer to the first element of the char array with a maximum length of 100 (and the \0 becomes the 101th character) and then concatenate two strings by overloading the + operator. Everything is running ok, I checked the code by running sample test cases like input1 = "YX", input2 = "GH" and I get result = "YX GH" but the thing printed on the console is Y (only the first character of the string).

Some things I tested with my code:

If I use the loop in the display function (to display each character of the string) anywhere else in the code, like in the constructor, I get a proper output but somehow it is failing in the display function. This is happening because the cout is working only when called for the first time (for some reason I don't understand). Like if I add the statement cout<<"Hello"<<endl; or cout<<*a<<*a<<endl; before the for loop in my display function, it only prints Hello or Y (respectively) and nothing else.

I even tried flushing cout and it did not change anything but I knew that would happen because the endl after the end of the for loop should be flushing it itself.


Solution

  • So as stated by Botje in his comment, I am defining a local variable temp in the operator+ function and passing the array to the String constructor (which is passed by reference) and so after the operator+ is completed, nobody can stop the contents at the next memory locations from being changed and the compiler I was using intitially was not letting me access the memory locations that I had no access to (because it an online compiler which freed the next memory locations).

    I checked on a local compiler on my PC and it printed the first letter as before and some random characters. Like in the example stated before of YX and GH, the output was Y?1a or Y3p? or some random stuff after Y.

    So I defined the temp array outside the operator+ function and when I ran my code again, I got the desired output which confirmed the error was because of local arrays and the pass by reference property of arrays.

    This are my edited stringConcat.cpp and stringConcat.h files:

    stringConcat.h:

    class String
    {
    public:
        char *a;
        int length;
        char temp[202];
        String(char b[], int size=101)
        {
            a = &b[0];
            length = size;
        }
        String operator+(const String &other);
        void display();
    };
    

    stringConcat.cpp:

    #include <iostream>
    #include "stringConcat.h"
    using namespace std;
    String String::operator+(const String &other)
    {
        int counter = 0;
        for(int i = 0; i < length; i++)
        {
            if(*(a+i) == '\0')
                break;
            temp[counter++] = *(a+i);
        }
        temp[counter++] = ' ';
        for(int i = 0; i < other.length; i++)
        {
            if(*(other.a+i) == '\0')
                break;
            temp[counter++] = *(other.a+i);
        }
        temp[counter++] = '\0';
        return String(temp, counter);
    }
    void String::display()
    {
        for(int i = 0; i < length; i++)
        {
            if(*(a+i) == '\0')
                break;
            cout<<*(a+i);
        }
        cout<<endl;
    }
    

    But again, as Bortje said, now we have the same memory location for all strings created by the operator+ function. Like if we have another String str3 and we do String result_new = str1 + str3, we overwrite the String result (formed from str1 + str2) because of the fact that the char temp[202] is same - the attribute of the object str1 for both cases.

    So I changed my stringConcat.cpp and stringConcat.h files to get the final files:

    stringConcat.h:

    class String
    {
    public:
        char *a;
        int length;
        String(char b[], int size=101)
        {
            a = &b[0];
            length = size;
        }
        String operator+(const String &other);
        void display();
    };
    

    stringConcat.cpp:

    #include <iostream>
    #include "stringConcat.h"
    using namespace std;
    String String::operator+(const String &other)
    {
        int counter = 0;
        int total = length + other.length;
        char *temp = new char[total];
        for(int i = 0; i < length; i++)
        {
            if(*(a+i) == '\0')
                break;
            temp[counter++] = *(a+i);
        }
        temp[counter++] = ' ';
        for(int i = 0; i < other.length; i++)
        {
            if(*(other.a+i) == '\0')
                break;
            temp[counter++] = *(other.a+i);
        }
        temp[counter++] = '\0';
        return String(temp, counter);
    }
    void String::display()
    {
        for(int i = 0; i < length; i++)
        {
            if(*(a+i) == '\0')
                break;
            cout<<*(a+i);
        }
        cout<<endl;
    }