There are a some functions in C that you should never use. Functions that make your program vulnerable to attacks (such as buffer overflow attacks) or that might crash your program or that might corrupt memory and let your program in an undefined state. strncpy is one of them.

char *strncpy(char *dest, const char *src, size_t n);

This function copies at most n bytes the string pointed to by src, including the terminating null byte ('\0'), to the buffer pointed to by dest. The problem with this function (an there's even a warning in the man page) it's that it does not always null-terminate the string dest. This happens when there is no null byte in the fist n bytes of src and will make any function that assumes that the string dst is null-terminated misbehave (e.g. strlen, strcat, etc)

Consider this very simple program:

#include <stdio.h>
#include <string.h>

struct s {
    char s1[3];
    char s2[4];
};

int main() {
    struct s s;

    strncpy(s.s1, "foo", sizeof(s.s1));
    strncpy(s.s2, "bar", sizeof(s.s2));
    printf("%s %s\n", s.s1, s.s2);

    return 0;
}

When running the program above we get the output:

foobar bar

which, at fist may seem weird, but happens because the string s1 is not null terminated and the memory layout of the structure makes printf consider that the string for the first %s specifier ends at the null byte of the field s2.

To fix this issue, use instead snprintf, which always null-terminates the string:

snprintf(dest, n, "%s", src);

or use a wrapper for the strncpy like:

char *mstrncpy(char *dest, const char *src, size_t n)
{
        strncpy(dest, src, n);
        if (n)
                dest[n - 1] = 0;
        return dest;
}

P.S. The same goes for strcpy which is vulnerable to buffer overflows, especially if using fixed length buffers and not checking input.