17

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?
Amit G.
  • 2,546
  • 2
  • 22
  • 30
Koray
  • 467
  • 1
  • 5
  • 12
  • 3
    Option 2 is wrong, should be `sizeof(char)` which is always `1`. – hmjd Oct 17 '12 at 13:46
  • You have the "c" tag, but "new char[ARRAY_LENGTH]" is not valid C syntax. – Barmar Oct 17 '12 at 13:47
  • 1
    None of your alternatives are even correct! The proper way to call memset would have been `memset(buffer, '\0', sizeof(char) * ARRAY_LENGTH);`. However, the syntax specified by Luchian is better. – Lundin Oct 17 '12 at 13:47
  • Sorry for the tag errors and typo- just edited the question – Koray Oct 17 '12 at 13:48
  • @Lundin sizeof(char) is by definition 1. When I see it I actually use it as a sign to indicate extra careful review of the code. – Art Oct 17 '12 at 13:49
  • Don't use `new[]` in C++, use the appropriate container. – GManNickG Oct 17 '12 at 16:19

8 Answers8

23

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.

Dirk Holsopple
  • 8,731
  • 1
  • 24
  • 37
  • 1
    Second option is using `sizeof(char)` not `sizeof(char*)` or I miss something? – PiotrNycz Oct 17 '12 at 14:13
  • @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 Oct 17 '12 at 14:26
  • @LuchianGrigore: that just makes other people's answers look wrong -- three people said option 2 was OK. – Steve Jessop Oct 17 '12 at 14:33
  • Not so important, but, passing 0 instead of '\0' works as well. – Bharath Oct 01 '15 at 14:41
  • Suppose the array is `char a[200][200];`. Does `memset(a, 0, sizeof(a));` works fine? – asn Jun 22 '19 at 19:12
13

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 );
Sinipelto
  • 147
  • 1
  • 8
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
6

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.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
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);.

Jamal
  • 763
  • 7
  • 22
  • 32
PiotrNycz
  • 23,099
  • 7
  • 66
  • 112
2

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.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • "it's a very ungood idea". Yeah? Then how would you write code to handle an array of 8-bit hardware register values? – Lundin Oct 17 '12 at 13:52
  • 1
    @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 – Martin James Oct 17 '12 at 14:44
  • Since C++ 11, I whould use: `std::unique_ptr buffer(new char[ARRAY_LENGTH]());` and since C++ 14, I would use: `std::unique_pointer buffer = std::make_unique(ARRAY_LENGTH);` Or the alternative of shared pointer if it's required. – Amit G. Jul 29 '18 at 02:19
  • @AmitG.: Uhm. I'd prefer `auto buffer = make_unique(array_length);`, if I *had* to have a `new`-allocated raw array. – Cheers and hth. - Alf Jul 29 '18 at 03:37
1

Well, personally I like option 3:

memset( buffer, '\0', ARRAY_LENGTH )

ARRAY_LENGTH is exactly what I would like to fill in the memory.

Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
Simon Lau
  • 61
  • 1
  • 5
1

Since C++ 11, I whould choose:

#include <array>

std::array<char, ARRAY_LENGTH> buffer{ '\0' };

buffer.fill('\0');
Amit G.
  • 2,546
  • 2
  • 22
  • 30
  • 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? – Niko Feb 19 '19 at 14:55
0

Option 3: memset( buffer, '\0', ARRAY_LENGTH ): will give you only length of array but actually this parameter is total how much byte of memory.

Option 1: memset( buffer, '\0', sizeof(buffer) ): will give you wrong answer because, buffer is char*. sizeof(buffer) would not give you size of whole array only size of a pointer variable.

Option 2 is right.

taufique
  • 2,701
  • 1
  • 26
  • 40