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.