All of the reading I've done says that passing a non null-terminated char array to std::strlen
is undefined behavior and will likely cause the program to crash. However, the code below (compiled with g++ on Cygwin) works just fine.
What is going on here?
char test_cases[4][80] = {{'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!'}, {}, {'1'}, {'A', 'B', 'C'}};
size_t num_test_cases = std::size(test_cases); // C++17
for (size_t i = 0; i < num_test_cases; ++i)
{
std::cout << std::strlen(test_cases[i]) << std::endl;
}
Output:
13
0
1
3
The construction of arrays means any unused slots are conveniently set to zero size.
So what you wrote is entirely legal and consistent.
Had you defined your buffer size exactly right for "Hello, world!"
char test_cases[4][13]
You would have got the "broken" answer, and touched the edge of UB.
Also because you declared that as the first buffer, it will run on into the second buffer, so will give a wrong answer rather than some fatal error.
Actually, looking again, because you defined the second string as empty, you STILL wouldn't see an error, as the first byte of the overflowing data is perhaps also zero-filled!
I say perhaps, because {} with no value is actually NOT legal C. It is legal C++11, but I'm not entirely sure if the behaviour is to ensure all members are zeroed if the C++11 aggregate "style" initialisers are invoked. In fact, because of your output, {} must have done the "right" thing.
Usually there are so many zeros in memory that your strings will usually be terminated eventually! As @John mentioned, this is an opportunity for aliens to steal money from your bank account.