I am allocating space only for two characters but it fits all of them, if you run this it will print the whole string literal "hello my friend". How is that possible?
strcpy(str, "hello my friend"); means "copy this thing on the right into the memory starting at the location that the pointer named str is pointing to".
So it does. It writes over str[0], and then str[1], and then the next byte (which could contain any data at all and you have no idea what you're writing over), and then the next byte (which could contain any data at all and you have no idea what you're writing over), and then the next byte (which could contain any data at all and you have no idea what you're writing over), and so on. Why would it stop you?
If you try to write over memory that the operating system thinks isn't yours, it will segFault. Clearly, the memory right after str[1] is not memory the OS thinks isn't yours. You're still trashing whatever data is there, though.
Then, this: cout << str
This means "Output to screen the array of char that starts at the memory location str points to and finishes with a zero value". It does NOT mean "Output to screen str[0] and str[1]".