Really you want both a length, of the data actually in the string, and a capacity, marking how much memory is valid.
If I'm understanding the vulnerability right: strncmp takes three arguments, the beginning of the first string, the beginning of the second string, and the maximum number of bytes to compare. That maximum isn't quite a length or a capacity. It's a bound on the length, if one of the strings isn't null-terminated. But if you provide too small a maximum, it'll only compare the first few characters, and return a value based on that.
In particular they compared the target string to the user-provided string, with a user-provided length, so if you provide an empty string, it compares 0 bytes and returns success.
An API of the form strcmp(struct actual_string a, struct actual_string b) wouldn't have this problem - the actual string structures (instead of a char pointer) would provide a length for both strings, so the API wouldn't let you make this sort of error.
It's more convenient and safer to have these two variables packed together as a "string object" and have string functions operate on that - then they always know where the string starts and ends in memory.