I am building a custom string class. However, the user inputs give different output from the assigned-value one. For example: With the assigned values:
    #include"custom_string.h"
    int main() {
        string a = "Hello";
        string b = "World";
        string c = a + b;
        std::cout << "C string is: " << c << std::endl;
        std::cout << "Length of C string is: " << c.length() << std::endl;
        system("pause");
        return 1;
}
Then the output would be:
C string is: HelloWorld
Length of C string is: 10
In user input case:
    #include"custom_string.h"
        int main() {
            string a;
            string b;
            string c = a + b;
            std::cout << "Input a string: " << std::endl;
            std::cin >> a;
            std::cout << "Input b string: " << std::endl;
            std::cin >> b;
            std::cout << "C string is: " << c << std::endl;
            std::cout << "Length of C string is: " << c.length() << std::endl;
            system("pause");
            return 0;
}
Then the output would be:
Input a string:
Hello
Input b string:
World
C string is:
Length of C string is: 0
Here is the code source of "custom_string.h":
 #ifndef _STRING
        #define _STRING
        #include<iostream>
        #include<cstring>
        #define MAX 99999
        class string {
        private:
            char* s = nullptr; //Member of custom string
            unsigned int size = 0; // length of string (including '\0')
        public:
            string();
            ~string() { delete s; };
            string(char* );
            string(const char* );
            string(const string&);
            friend std::istream& operator >> (std::istream&, string&);
            friend std::ostream& operator << (std::ostream&, string&);
            friend string operator +(string, string);
            string& operator = (const string&);
            string& operator = (const char&);
            unsigned int length();
            char* output() const{
                return s;
            }
        };
        #endif
    string::string() :s{ nullptr } {
        size = 1;
        s = new char[size];
        s[0] = '\0';
    }
    string::string(char* source) {
        if (source == nullptr) {
            size = 1;
            s = new char[size];
            s[0] = '\0';
        }
        else {
            size_t i = 0;
            while (source[i] != '\0') { //To remove NULL/redundant elements of source array from istream assignment
                i++;
            }
            size = i + 1;
            s = new char[size];
            s[size - 1] = '\0';
            for (size_t k = 0; k < size - 1; k++) {
                s[k] = source[k];
            }
        }
    }
    string::string(const char* source) {
        if (source == nullptr) {
            size = 1;
            s = new char[size];
            s[0] = '\0';
        }
        else {
            size = strlen(source) + 1;
            s = new char[size];
            s[size - 1] = '\0';
            for (size_t k = 0; k < (size - 1); k++) {
                s[k] = source[k];
            }
        }
    }
    string::string(const string& t) {
        size = t.size;
        s = new char[size];
        for (size_t k = 0; k < size; k++) {
            s[k] = t.s[k];
        }
    }
    string& string::operator=(const string& source) {
        if (source.s == s) {
            return *this;
        }
        else {
            delete[] s;
            size = source.size;
            s = new char[size];
            for (size_t k = 0; k < size; k++) {
                s[k] = source.s[k];
            }
            return *this;
        }
    }
    string& string::operator=(const char&source) {
        const char* t = &source;
        if (t == nullptr) {
            size = 1;
            s = new char[size];
            s[0] = '\0';
        }
        else {
            size = strlen(t) + 1;
            s = new char[size];
            s[size - 1] = '\0';
            for (size_t k = 0; k < (size - 1); k++) {
                s[k] = t[k];
            }
        }
        return* this;
    }
    string operator +(string a, string b) {
        if (a.s == nullptr ) { return b; }
        if (b.s == nullptr ) { return a; }
        string t;
        size_t k = 0;
        size_t l = 0;
        t.size = (a.size + b.size) - 1;
        t.s = new char[t.size];
        while (a.s[k] != '\0' && k < a.size && k < t.size) {
            t.s[k] = a.s[k];
            k++;
        }
        while (k < t.size && l < b.size) {
            t.s[k] = b.s[l];
            k++;
            l++;
        }
        return t;
    }
    std::istream& operator >> (std::istream& is, string& source) {
        char* t = new char[MAX];
        is >> t;
        source = string{ t };
        delete[] t;
        return is;
    }
    
    std::ostream& operator << (std::ostream& os, string& source) {
        os << source.output();
        return os;
    }
unsigned int string::length() {
    return (size - 1); //Ignore the '\0' character
}
I do not know what makes the difference between to cases. Maybe I have missed some necessary commands.
Edit: I have known assigning c after input a and b will solve the problem. However, I don't want to do so because I want to separate assigning part and complying part in order to have neat code. Is there any way to fix error without assigning c after input a and b?
 
    