Does the constructor of the copy std :: string add a null character to the end by itself?

advertisements

First I was doing,

#include <iostream>
#include <string>

void foo (std::string s) {
    std::cout << s << std::endl;
}

int main () {
    char st[] = "0";
    st[1] = '[';
    std::string s (st);
    std::cout << s << std::endl;
    return 0;
}

It shows junk when I send to the stream object cout using stream insertion operator (guess it is a normal behaviour).

Then I checked by passing to a function foo by value. I'm doing something like this now.

    foo (s);

    // after calling foo () value printed by the
    // std::cout is changed. it takes care of NULL character ('\0')
    std::cout << s << std::endl;

It doesn't show junk after 0[ anymore. Why?

My question is, I passed the string in foo () by value. There run a copy constructor before the body of the foo () is run. But still doesn't make sense. How can this copyctor change parameter passed from main () by value?

Thanks in advance.


char st[] = "0";

Pop Quiz: How big is st?

Answer: Two chars One for the "0", and one for the null-terminator.

Then you go and overwrite the null terminator:

st[1] = '[';

...and try to construct a string based on that:

std::string s (st);

The string constructor which takes a const char* is being invoked here, and the way it works is it looks for the null-terminator. Since you blew it away, it's going to run past the end of st. Running past the end of st evokes Undefined Behavior, and is the reason why you see garbage.

Its important to note that Undefined Behavior means anything can happen. "Anything" here includes "exactly what I want to happen." It doesn't necessarily that you'll get garbage output, or that your program will crash. Trying to reason out why UB manifests itself in this way or that is an unreasonable effort.