0

I'm new to C++ and i was experimenting a bit with some of its features (mainly templates, pointers, OOP) trying to build a string class, when I got stuck in this problem. The incriminated code looks like this:

string.h

...
private:
        char* value;
...
public:
        string();
...

string.cpp

string::string() : value( '\0' ) {
    std::cout << "Initialized string value: " << this->value << "blablabla" << std::endl;
}

What I thought would happen is that the "value" class' memeber got initialized as an empty string as soon as the constructor got called, but apparently I was wrong, since when I call it, I see this on the console:

"Initialized string value: "

Now, why does the output get kind of truncated once it prints the "value" class member? What am I doing wrong?

Federico Luzzi
  • 128
  • 1
  • 10
  • value is not `char`, value is `char *`. – Tony J Apr 20 '17 at 18:28
  • `'\0'` is not the empty string, it's the null character. The empty string looks like this: `""`. – molbdnilo Apr 20 '17 at 18:28
  • 2
    `value( '\0' )` is trying to convert the char value 0 to `char*`. You probably meant `value("")`. – cdhowie Apr 20 '17 at 18:28
  • Typo. A string uses `"` not `'`. The later is for a character. Change `'\0'` to `"\0"`. – NathanOliver Apr 20 '17 at 18:28
  • One question: why do I have to use double quotes? I thought that a char was identified by single quotes, and value is a pointer to a char – Federico Luzzi Apr 20 '17 at 18:32
  • 2
    You can't initialize a `char*` pointer with a single `char` value, it needs to be initialized with a memory address of a `char`. Using single-quotes declares a single `char`, whereas using double-quotes declares a `const char[]` array, which then decays into a pointer. – Remy Lebeau Apr 20 '17 at 18:41

3 Answers3

1

Your code

string::string() : value( '\0' )

is assigning an integer value of 0, an equivalent of a nullptr or just simply NULL, to a variable that is meant to be a pointer to the first character in your string.

One thing you can do to make that particular code work is to specify an actual string for the initialization:

string::string() : value( "" ) // note the double-quotes to denote a string

Of course you should also implement the proper handling of that char* value; buffer, i.e. make sure you allocate the string when assigning values to it, free the memory when you no longer need it, etc.

N.B.
In no way do I advocate for actually doing it this way! I'm only providing an example that would work for this short code snippet. If you were to go with a default value I'd suggest you have a static member variable that you use as your "empty string" initializer. That way, at least, you can check whether your string is empty when you need to either allocate a buffer or free the memory.

In your .h file:

private:
    static char empty[];

And in your .cpp file:

char string::empty[] = {'\0'};

string::string() : value(empty) {...}
YePhIcK
  • 5,816
  • 2
  • 27
  • 52
  • One question about when you say that I have to manage the allocation/deallocation of memory: could that be done with a pointer to the actual string characters and a side variable telling me the length of the actual string so that I know how many chars I could read before going outside the correct values? – Federico Luzzi Apr 20 '17 at 18:40
  • It can be any way you make it ;-) What you are suggesting sounds like an implementation using an `std::vector'. Or you can it implemented as a `struct buf{int len = 0; char * str = nullptr;}`. Or something totally different - that is the beauty of writing your own implementation – YePhIcK Apr 20 '17 at 18:48
  • `char* string::empty = "";` is ill-formed. `""` is a `const char []` – Richard Hodges Apr 20 '17 at 19:02
  • @RichardHodges: assigning a string literal to a non-const `char*` is deprecated in C++11 and later, but older versions accept it. However, for the sake of correctness, it should be this in all versions: `static const char *empty; ... const char* string::empty = "";` – Remy Lebeau Apr 20 '17 at 19:04
  • Or just `char string::empty[] = {'\0'};`? Let me update the answer. – YePhIcK Apr 20 '17 at 19:08
1

You are initializing your char* with a numeric value of 0, aka NULL. Passing a NULL char* pointer to operator<< is undefined behavior. That is why you are seeing truncated output - std::cin is entering a failure state and thus ignores the subsequent operator<< calls.

If you want operator<< to succeed then you need to change the initialization of your char* pointer to a real memory address (even if just to a nul character), eg:

string::string() : value( "\0" )

Or simply (the \0 is implicit):

string::string() : value( "" )

Using " instead of ' defines the literal as a const char[] array in static memory, and an array decays into a pointer.

Now, passing the char* to operator<< will have well-defined behavior.

However, if you want your char* to be NULL when your string is empty, then you need to take care not to pass the char* to operator<< if it is NULL, eg:

class myString
{
private:
    char* value;
    ...

public:
    myString();
    void print(std::ostream &out) const;
};

std::ostream& operator<<(std::ostream &out, const myString &str);

myString::mySstring() : value( 0 ) {}

void myString::print(std::ostream &out) const
{
    if (value) out << value;
}

std::ostream& operator<<(std::ostream &out, const myString &str)
{
    str.print(out);
    return out;
}

myString s;
std::cout << "Initialized string value: " << s << "blablabla" << std::endl;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

When you pass char* to operator<< of std::cout, your char* will be treated as a C-string, which implies it will be dereferenced.

In your specific case value pointer is initialized with '\0' - as your compiler might have warned you, it is an implicit way to create a null pointer.

Dereferencing a null pointer is undefined behavior, and that explains the abrupt truncation of your output.

Since you need your pointer to be dereferenced, you want to make sure it points to some actual valid memory. That will require proper memory management of your class, and that topic will most certainly not fit into one SO answer.

Consider reading some tutorials on dynamic memory in C++ as a start :)

Ap31
  • 3,244
  • 1
  • 18
  • 25