How to memset char array with null terminating character?

95,743

Solution 1

Options one and two are just wrong. The first one uses the size of a pointer instead of the size of the array, so it probably won't write to the whole array. The second uses sizeof(char*) instead of sizeof(char) so it will write past the end of the array. Option 3 is okay. You could also use this

memset( buffer, '\0', sizeof(char)*ARRAY_LENGTH );

but sizeof(char) is guaranteed to be 1.

Solution 2

The idiomatic way is value-initializing the array:

char* buffer = new char [ARRAY_LENGTH]();

Option 1 only sets the first sizeof(char*) bytes to 0, or runs into undefined behavior if ARRAY_LENGTH < sizeof(char*). This is due to using the size of the pointer instead of the size of the type.

Option 2 runs into undefined behavior because you're attempting to set more than ARRAY_LENGTH bytes. sizeof(char*) is almost certainly greater than 1.

Since this is C++ though (no new in C), I suggest you use a std::string instead.

For C (assuming malloc instead of new[]), you can use

memset( buffer, 0, ARRAY_LENGTH );

Solution 3

Since the question keeps changing, I define:

1: memset( buffer, '\0', sizeof(buffer) );

2a: memset( buffer, '\0', sizeof(char*) * ARRAY_LENGTH );

2b: memset( buffer, '\0', sizeof(char) * ARRAY_LENGTH );

3: memset( buffer, '\0', ARRAY_LENGTH );

If the question is merely, "what is the correct way to call memset" rather than "what is the best way to zero this array", then either 2b or 3 is correct. 1 and 2a are wrong.

You can have a style war over 2b vs 3: whether to include the sizeof(char) or not -- some people leave it out because it's redundant (I usually do), other people put it in to create a kind of consistency with the same code setting an array of int. That is to say they always multiply a size by a number of elements, even though they know the size is 1. One possible conclusion is that the "safest" way to memset the array pointed to by buffer is:

std::memset(buffer, 0, sizeof(*buffer) * ARRAY_LENGTH);

This code remains correct if the type of buffer changes, provided of course that it continues to have ARRAY_LENGTH elements of whatever type that is, and provided that all-bits-zero remains the correct initial value.

Another option beloved of "C++ is not C" programmers, is:

/* never mind how buffer is allocated */
std::fill(buffer, buffer + ARRAY_LENGTH, 0);

If you care, you can then check for yourself whether or not your compiler optimizes this to the same code to which it optimizes the equivalent call to std::memset.

char *buffer = new char [ARRAY_LENGTH](); is nifty but almost useless in C++ in practice because you pretty much never allocate an array with new in the first place.

std::string buffer(ARRAY_LENGTH, 0); introduces a particular way of managing the buffer, which may or may not be what you want but often is. There's a lot to be said for char buffer[ARRAY_LENGTH] = {0}; in some cases.

Solution 4

  • Does any of these have significant advantage over other(s)?
  • What kind of issues can I face with with usages 1, 2 or 3?

1st is wrong, because sizeof(buffer) == sizeof(char*).

2nd and 3rd are OK.

  • What is the best way to handle this request?

Why not just:

buffer[0] = '\0';

If this is a char array, why bother with the rest of the characters? With the first byte set to zero, you have the equivalent of "" in your buffer.

Of course, if you really insist on having all of buffer zeroed, use the answer with std::fill - this is the proper way. I mean std::fill(buffer, buffer + ARRAY_LENGTH, 0);.

Solution 5

If you absolutely must use a raw array in C++ (it's a very ungood idea), do it like this:

char* buffer = new char [ARRAY_LENGTH]();

For C++ memset is generally the last refuge of the incompetent, although I learned within the last few months that for acceptable performance, with current tools, it's necessary to go down to that level when one implements one's own string class.

Instead of these raw arrays etc., which can appear to need memset, use e.g. std::string (for the above case), std::vector, std::array etc.

Share:
95,743
Koray
Author by

Koray

Updated on February 07, 2021

Comments

  • Koray
    Koray over 3 years

    What is the correct and safest way to memset the whole character array with the null terminating character? I can list a few usages:

    ...
    char* buffer = new char [ARRAY_LENGTH];
    
    //Option 1:             memset( buffer, '\0', sizeof(buffer) );
    //Option 2 before edit: memset( buffer, '\0', sizeof(char*) * ARRAY_LENGTH );
    //Option 2 after edit:  memset( buffer, '\0', sizeof(char) * ARRAY_LENGTH );
    //Option 3:             memset( buffer, '\0', ARRAY_LENGTH );
    ...
    
    • Does any of these have significant advantage over other(s)?
    • What kind of issues can I face with with usages 1, 2 or 3?
    • What is the best way to handle this request?
  • Lundin
    Lundin over 11 years
    "it's a very ungood idea". Yeah? Then how would you write code to handle an array of 8-bit hardware register values?
  • PiotrNycz
    PiotrNycz over 11 years
    Second option is using sizeof(char) not sizeof(char*) or I miss something?
  • Steve Jessop
    Steve Jessop over 11 years
    @PiotrNycz: judging by hmjd's comment under the question, the question originally said sizeof(char*) in option 2 but was changed within the edit window, so there's no edit history.
  • Steve Jessop
    Steve Jessop over 11 years
    @LuchianGrigore: that just makes other people's answers look wrong -- three people said option 2 was OK.
  • Martin James
    Martin James over 11 years
    @Lundin - you should probably not ask these guys - they will come up with some nasty tweak of the std::vector metadata so that it points at the memory-mapped hardware <g>
  • Bharath
    Bharath over 8 years
    Not so important, but, passing 0 instead of '\0' works as well.
  • Amit G.
    Amit G. almost 6 years
    Since C++ 11, I whould use: std::unique_ptr<char[]> buffer(new char[ARRAY_LENGTH]()); and since C++ 14, I would use: std::unique_pointer<char[]> buffer = std::make_unique<char[]>(ARRAY_LENGTH); Or the alternative of shared pointer if it's required.
  • Cheers and hth. - Alf
    Cheers and hth. - Alf almost 6 years
    @AmitG.: Uhm. I'd prefer auto buffer = make_unique<char[]>(array_length);, if I had to have a new-allocated raw array.
  • Niko
    Niko about 5 years
    Can you elaborate on why? I find this even less readable than memset() and you won't be able to compile it with old compilers. Does it provide some advantage on runtime?
  • ajaysinghnegi
    ajaysinghnegi almost 5 years
    Suppose the array is char a[200][200];. Does memset(a, 0, sizeof(a)); works fine?