"Am I entering undefined behavior?"
Yes. A region at the end of a[] has been written over. It worked, this time, but might have belonged to something else.
Here I use a struct to control memory layout, and demonstrate it:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
struct S {
char a[8];
char b[5];
char c[7];
};
S s;
strcpy( s.a , "Hello, " );
strcpy( s.b , "Foo!" );
strcpy( s.c , "world!" );
strcat(s.a, s.c);
cout << s.a << endl;
cout << s.b << endl;
cin.get();
return 0;
}
This outputs:
Hello, world!
orld!
Instead of:
Hello, world!
Foo!
The strcat() has stomped all over b[].
Please note that in a real life example such bugs may be far more subtle, and lead you to wondering why perfectly innocent function calls 250 lines later crash and burn horribly. ;-)
EDIT: May I also recommend that you use strcat_s, instead? Or, even better, std::strings:
#include <string>
#include <iostream>
using namespace std;
int main()
{
string a = "Hello, ";
string b = "world!";
a = a + b;
cout << a;
}