Is it recommended to use memset before strncpy?

Normally when we want to copy the contents of a given string into another string we can use the functions strncat or strncpy.

Using strncat

The use of strncat to copy strings is kind of "wrong", because this function serves to concatenate/join strings and not copy, but still it is possible and for this just use the function memset in the Target string and then apply the function strncat thus preventing the target string from receiving garbage. Follow the code below for a larger view of the thing:

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

int main(void){

    char foo[15];

    printf("\nFoo (lixo): %s\n", foo);

    memset(foo, 0, 15);

    strncat(foo, "BOING 737", 10);

    printf("\nFoo: %s\n", foo);

    return 0;
}

Using strncpy

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

int main(void){

    char foo[15];

    printf("\nFoo (lixo): %s\n", foo);

    strncpy(foo, "BOING 737", 10);

    printf("\nFoo: %s\n", foo);

    return 0;
}

Now comes the question: Would it be necessary, for precautionary reasons in order to avoid garbage, to use memset before strncpy?

Author: Victor Stafusa, 2018-07-19

2 answers

That is not the issue to be addressed. In cases where the Pointer could be used containing garbage, probably the logic of the algorithm / program / function is wrong, and putting a memset there would not make it correct.

In cases where the algorithm is correct without using memset and the garbage is never used, then putting memset there will not help at all.

In cases where without memset, the logic is wrong and when adding it, it is correct, so that so i.e.. In this case memset is initializing memory with a bunch of zeros. However, it is not possible to generalize and say that this would be a universal solution, although certainly it is frequent.

There are cases where the array should be initialized with something else, such as whitespace or a predetermined text or something else. In these cases, adding memset probably won't help.

In the end, the question boils down to how this memory must be initialized. memset is just one of the ways to boot, but it's not the only one. The algorithm / program / function should ensure that the memory to be used has been initialized, but this is no reason to aggressively initialize anything even if it is not necessary.

How to use memset+strncat or strncpy, strncpy should perform better, but this will only be measurable and meaningful if it is within a loop that runs at least a few million times or if it is something you use to process amounts of text equivalent to whole books and that is not something that has the processing time dominated by some other more complex operation. That is, it will probably have no significant difference.

However, the main reason for using strncpy is that your intention is much clearer to anyone who is reading the code (even if it is yourself months or years later). Use memset+strncat it's something to say the least Strange.

If it is really necessary to zero the entire buffer before using it, I would recommend using memset+strncpy. But if it is not necessary to zero it, just for anything after the null Terminator to be ignored, then strncpy alone would be enough.

 2
Author: Victor Stafusa, 2018-07-19 19:21:18

The documentation of strncpy answer your question.

Citing only the relevant parties:

If the end of the source C string (...) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it

Translating:

If the string to be copied has fewer characters than the indicated size, zeros are placed at the end until the size.

These zeros end up playing the Terminator, even if the original string doesn't have it, and so you'll never see any garbage in the string, as functions that work on strings stop at the first Terminator.

No null-character is implicitly appended at the end of destination if source is longer than num. Thus, in this case, destination shall not be considered a null terminated C string (...).

Translating:

None Terminator character is added at the end of the destination if the string size is greater than the specified amount. And for this reason the resulting string will not be considered a NULL-terminated C string.

I.e.:

  • if you copy fewer characters than the given size, you will never see garbage, assuming you copy a valid string with Terminator.
  • if you copy more characters than the indicated size you will usually get an unfinished string and by that picks up garbage.

Examples:

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

int main(void){

    //Teste para copia com menos caracteres que o numero indicado
    char foo2[] = "outra string!!!";
    printf("\nFoo (lixo): %s\n", foo2); //Foo (lixo): outra string!!!
    strncpy(foo2, "BOING 737", 10);
    printf("\nFoo: %s\n", foo2); //Foo: BOING 737

    //Teste para copia com mais caracteres que o numero indicado
    char foo[] = "outra string!!!"; 
    printf("\nFoo (lixo): %s\n", foo); //Foo (lixo): outra string!!!
    strncpy(foo, "BOING 737", 5);
    printf("\nFoo: %s\n", foo); //Foo: BOING string!!!

    return 0;
}

I applied an initial string to make the tests more evident.

Test yourself on Ideone

Conclusion:

If you are sure that you are copying a complete string (with Terminator) and the size is less than or equal to that indicated in strncpy then you do not need to do memset. If you are not sure of this the best is to play it safe and apply the memset.

It is worth remembering that much, if not even all read functions, such as scanf, Put The Terminator in the read string, making it unnecessary to do any type of memset beforehand.

 1
Author: Isac, 2018-07-19 21:46:04