C'è una concezione errata di fondo su strncpy, che deriva dal fatto che è chiamata in maniera stupida.
strncpy non nasce come versione "sicura" di strcpy, ma come una funzione che non c'entra niente per operare su buffer a lunghezza fissata (non su stringhe NUL-terminate), per cui scrive gli zeri solo come padding, senza garantire che la stringa sia effettivamente terminata. Ergo, nei casi "buoni" perde tempo a scrivere degli zeri inutili, in quelli "cattivi" lascia la stringa non terminata.
L'equivalente-strcpy a lunghezza limitata (non standard, presente solo su alcuni compilatori) si chiama in genere strlcpy. In ogni caso, la puoi facilmente implementare "a mano":
codice:
void mystrlcpy(char * dst, const char * restrict src, size_t size) {
    if(!size) return 0;
    while(*src && size) {
        *dst = *src;
        dst++; src++; size--;
    }
    dst[-1]=0;
}