Question

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.

Was it helpful?

Solution

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.

It's 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.

OTHER TIPS

People are telling you about undefined behaviour. That's great, but you already know that.

In practice, the key here is that your first "junk" character may well be a '\0' character itself, in which case you won't see any bytes further than that.

You can't just assume that you're going to see at least 20 arbitrary characters, because one completely plausible outcome of your code is that you see 0 arbitrary characters.

In short, you're attempting to rationalise the unrationalisable; stop it!

After these two lines:

char st[] = "0";
st[1] = '[';

st is not a null terminated string. std::string(char const*) expects a null terminated string. Since the input to the constructor of std:string does not meet that criterion, you are entering undefined behavior territory. Anything could happen after that.

This line:

char st[] = "0";

causes the compiler to allocate a 2 byte array fixed-size array and fill it with "0\0" (ASCII 0 followed by a null character). This line

st[1] = '[';

then assigns '[' to the location previously occupied by the NULL, destroying the null-termination of your string. Then this line

std::string s (st);

will start at the beginning of st and keep copying chars into s until it finds a null somewhere in memory. That's why you're seeing garbage.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top