That’s because strncpy does not return a nul-terminated (“C”) strings, but a fixed-size nul-padded strings.
That, as it turns out, is the case of most (but not all) strn* functions.
Of course strncpy adds the injury that it’s specified to alllow nul-terminated inputs (it stops at the first nul byte, before filling the target buffer with nuls).
It also, in some situations, returns a *string" that doesn't have the null terminator, which means it is giving the caller something that literally isn't a string.
To be pedantic, they're pointers to char. Nothing more. Calling them array confuses non-C coders. The length is just an unenforced contract and has to be passed.
It's a pointer to a chunk of memory which contains an array of characters. You pass around the pointer because copying an array is expensive and wasteful.
I think (or hope) the concepts are pretty clear if you understand what a pointer is.
strncpy() can make a string into a non-string (depending on size), which is clearly bad.