Is it recommended to use memset before strncpy?

Asked

Viewed 141 times

2

Usually when we want to copy the contents of a particular 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" as this function serves to concaterate/join strings and not copy, but still is possible and for that just use the function memset in 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: It would be necessary, for precautionary reasons in order to avoid garbage, to use memset before strncpy?

2 answers

3

That is not the issue to be addressed. In cases where the pointer could be used containing garbage, probably the algorithm/program/function logic is wrong, and put a memset It wouldn’t make her right.

In cases where the algorithm is correct without using the memset and the garbage is never used, so put the memset there won’t help at all.

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

There are cases where the array should be initialized with something else, such as blanks or a predetermined text or something else. In such cases, add the memset probably won’t help you.

In the end, the question is reduced on how this memory should be initialized. The memset It’s just one of the ways to initialize, but it’s not the only way. 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.

As to use memset+strncat or strncpy, the strncpy it shall perform better, but this will only be measurable and meaningful if you’re inside a loop that runs at least a few million times or if it’s something you use to process text amounts equivalent to entire books and not something that has the processing time dominated by some other more complex operation. I mean, there’s probably no significant difference.

However, the main reason to use the strncpy is that your intention becomes much clearer to anyone reading the code (even if it is yourself months or years later). Use memset+strncat is something at least strange.

If it is really necessary to reset the whole buffer before using it, I would recommend using memset+strncpy. But if it is not necessary to do so, just by ignoring anything after the null terminator, then the strncpy alone would be enough.

1

The documentation of strncpy answers your question.

Citing only the parts that matter:

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 given size, zeros are placed at the end until the size is reached.

These zeroes end up being a terminator, even if the original string does not have it, and so you will never see any junk in the string, as functions that work in 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:

No terminator characters are 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 string C ending with null.

That is to say:

  • If you copy fewer characters than the given size, you will never see trash, assuming you copy a valid string with terminator.
  • If you copy more characters than the given general rule will end up with an unfinished string and so picks up trash.

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

Completion:

If you are sure that you are copying a full string (with terminator) and the size is less than or equal to the one indicated in strncpy then you don’t have to memset. If you’re not sure about this, it’s best to play it safe and apply the memset.

It is worth remembering that much, if not even all reading functions such as scanf, put the terminator in the read string, making it unnecessary to do any kind of memset beforehand.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.