Pointer assignments do not copy strings

You can use the = operator to copy integers, but you cannot use the = operator to copy strings in C. Strings in C are represented as arrays of characters with a terminating null-character, so using the = operator will only save the address (pointer) of a string.

#include <stdio.h>

int main(void) {
    int a = 10, b;
    char c[] = "abc", *d;

    b = a; /* Integer is copied */
    a = 20; /* Modifying a leaves b unchanged - b is a 'deep copy' of a */
    printf("%d %d\\n", a, b); /* "20 10" will be printed */

    d = c; 
    /* Only copies the address of the string - 
    there is still only one string stored in memory */
    
    c[1] = 'x';
    /* Modifies the original string - d[1] = 'x' will do exactly the same thing */

    printf("%s %s\\n", c, d); /* "axc axc" will be printed */

    return 0;
}

The above example compiled because we used char *d rather than char d[3]. Using the latter would cause a compiler error. You cannot assign to arrays in C.

#include <stdio.h>

int main(void) {
    char a[] = "abc";
    char b[8];

    b = a; /* compile error */
    printf("%s\\n", b);

    return 0;
}

Copying strings using standard functions

strcpy()

To actually copy strings, [strcpy()](<http://linux.die.net/man/3/strcpy>) function is available in string.h. Enough space must be allocated for the destination before copying.

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

int main(void) {
    char a[] = "abc";
    char b[8];

    strcpy(b, a); /* think "b special equals a" */
    printf("%s\\n", b); /* "abc" will be printed */

    return 0;
}

snprintf()

To avoid buffer overrun, [snprintf()](<http://pubs.opengroup.org/onlinepubs/9699919799/functions/snprintf.html>) may be used. It is not the best solution performance-wise since it has to parse the template string, but it is the only buffer limit-safe function for copying strings readily-available in standard library, that can be used without any extra steps.

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

int main(void) {
    char a[] = "012345678901234567890";
    char b[8];

#if 0
    strcpy(b, a); /* causes buffer overrun (undefined behavior), so do not execute this here! */
#endif

    snprintf(b, sizeof(b), "%s", a); /* does not cause buffer overrun */
    printf("%s\\n", b); /* "0123456" will be printed */

    return 0;
}

strncat()

A second option, with better performance, is to use [strncat()](<http://pubs.opengroup.org/onlinepubs/9699919799/functions/strncat.html>) (a buffer overflow checking version of strcat()) - it takes a third argument that tells it the maximum number of bytes to copy:

char dest[32];

dest[0] = '\\0';
strncat(dest, source, sizeof(dest) - 1);
    /* copies up to the first (sizeof(dest) - 1) elements of source into dest,
    then puts a \\0 on the end of dest */

Note that this formulation use sizeof(dest) - 1; this is crucial because strncat() always adds a null byte (good), but doesn’t count that in the size of the string (a cause of confusion and buffer overwrites).

Also note that the alternative — concatenating after a non-empty string — is even more fraught. Consider:

char dst[24] = "Clownfish: ";
char src[] = "Marvin and Nemo";
size_t len = strlen(dst);

strncat(dst, src, sizeof(dst) - len - 1);
printf("%zu: [%s]\\n", strlen(dst), dst);

The output is:

23: [Clownfish: Marvin and N]