50

Is it not possible to use memset on an array of integers? I tried the following memset call and didn't get the correct integer values in the int array.

int arr[5];
memset (arr, -1, sizeof(arr)/sizeof(int));

Values I got are:

arr[0] = -1
arr[1] = 255
arr[2] = 0
arr[3] = 0
arr[4] = 0
Ravi Gupta
  • 6,258
  • 17
  • 56
  • 79

6 Answers6

87

Just change to memset (arr, -1, sizeof(arr));

Note that for other values than 0 and -1 this would not work since memset sets the byte values for the block of memory that starts at the variable indicated by *ptr for the following num bytes.

void * memset ( void * ptr, int value, size_t num );

And since int is represented on more than one byte, you will not get the desired value for the integers in your array.

Exceptions:

  • 0 is an exception since, if you set all the bytes to 0, the value will be zero
  • -1 is another exception since, as Patrick highlighted -1 is 0xff (=255) in int8_t and 0xffffffff in int32_t

The reason you got:

arr[0] = -1
arr[1] = 255
arr[2] = 0
arr[3] = 0
arr[4] = 0

Is because, in your case, the length of an int is 4 bytes (32 bit representation), the length of your array in bytes being 20 (=5*4), and you only set 5 bytes to -1 (=255) instead of 20.

Ioan Paul Pirau
  • 2,733
  • 2
  • 23
  • 26
  • 7
    Well, in this particular case (for -1 as a value) memset actually works. Because -1 is 0xff in int8_t and 0xffffffff in int32_t and so on. IOW: memset works fine for 0 and -1 but is not very useful for all other cases. – Patrick B. Aug 26 '11 at 09:16
  • You are right Patrick, Thank you.. I changed my answer accordingly – Ioan Paul Pirau Aug 26 '11 at 09:22
  • 11
    @Patrick B. : it will work fine on many platforms, but not all. Not all platforms use two's complement, and you might also trigger trap representations by using `memset` to initialize an `int`. – Sander De Dycker Aug 26 '11 at 09:44
  • 2
    every int whose all four bytes have the same value can use memset, not only 0 and -1 – phuclv Dec 27 '13 at 01:31
  • @LưuVĩnhPhúc but are the representations besides 0 guaranteed? http://stackoverflow.com/q/11138188/895245 says yes for 0, but I think not for others because we don't know where the padding and sign bits are inside each int. – Ciro Santilli OurBigBook.com May 10 '16 at 18:35
  • *"The reason you got: arr[0] = -1 arr[1] = 255 arr[2] = 0 arr[3] = 0 arr[4] = 0 is because..."* - Incorrect. You´d forgotten one important thing. Since `arr` is not qualified with either `static` or `extern` and is apparently declared inside a function (probably `main()`), the values of the elements of `arr` are indeterminate by definition. Even with `arr[1]` you can not be sure which values the remaining bits in the next three bytes are consisted of. Thus, printing the elements of `a[1]` to `a[4]` is a clear case of Undefined Behavior. Only at `a[0]` you will be able to know the exact result. – RobertS supports Monica Cellio Mar 08 '20 at 11:23
41

Don't use memset to initialize anything else than single-byte data types.

At first sight, it might appear that it should work for initializing an int to 0 or -1 (and on many systems it will work), but then you're not taking into account the possibility that you might generate a trap representation, causing undefined behavior, or the fact that the integer representation is not necessarily two's complement.

The correct way to initialize an array of int to -1, is to loop over the array, and set each value explicitly.

Community
  • 1
  • 1
Sander De Dycker
  • 16,053
  • 1
  • 35
  • 40
  • 13
    I think this answer should be pondered by a clause such as "Don't use `memset()` ... **if you want to write absolutely portable code**". Most people neither write nor intend to write portable code. Most people call code "portable" when it works for two architectures. The word "correct" in "The correct way ..." could also be changed to "portable". If you're not trying to write absolutely portable code, it's neither more nor less correct. – Pascal Cuoq Aug 26 '11 at 16:38
  • +1 @Complicatedseebio couldn't agree more, far too many programmers jump down peoples throats with things like 'correct', and 'stl this'. Far too often they over look what's needed by the specific problem. – Adam Naylor Feb 15 '12 at 21:22
  • 9
    @Complicated see bio @Adam : The thing is though, that initializing an array of `int` using a loop is guaranteed to work in all cases, whereas using `memset` might fail to do it properly (or worse might _appear_ to work). I won't say you can't use `memset` if you have intimate knowledge of the platforms the code will run on, and know it won't cause an issue. But I don't have such knowledge about the platforms of everyone who might read this answer, so I prefer to play it safe. I hope that balances out some of the "extremes" (for argument sake) I used in my answer. – Sander De Dycker Feb 16 '12 at 08:23
  • 2
    Upvote for Sander, I didn't understand why the -1 wasn't working for me until I realized the machine I was working with wasn't 2-complement. – capitano666 Nov 16 '13 at 14:08
  • @capitano666 - just curious - what processor ("machine") were you using? – Frederick Nov 09 '16 at 22:59
  • @SanderDeDycker: If the array is of a type `int*_t`, it data is guaranteed to be stored in two's-complement without padding. As for non-two's-complement machines, I would be very surprised if there exist *any* conforming C99 implementations that are used to run production code but don't use two's-complement. Unisys may still be upgrading their compilers, but the manual I read didn't list any unsigned type longer than 36 bits. – supercat Nov 10 '16 at 19:53
  • @supercat : whether there are 0 or 1000 such implementations that are currently in use, does not change my point of view. I don't know how many there are, nor do I know whether readers of my answer use such implementations (archaic or otherwise), nor do I know whether such implementations might make a comeback in the future. All I know is that my recommendation will work on any conforming implementation. – Sander De Dycker Nov 11 '16 at 15:40
  • @SanderDeDycker: Any code which follows the common advice of favoring uint32_t etc. over int, long, etc. will be limited to implementations which store signed versions of the named-size types in two's-complement format (I think the Standard should have allowed implementations to define uint32_t if they have a 32-bit unsigned type with no padding or trap representations, without regard for whether they have a corresponding two's-complement signed type, but the Standard forbids that). I do not think there is value in adding any complexity to code for purposes of supporting... – supercat Nov 11 '16 at 16:10
  • ...implementations that do not exist and are extremely unlikely to exist in future. – supercat Nov 11 '16 at 16:11
  • @Frederick, I'm afraid I don't remember what I was working with 3 years ago, maybe it was a Cubieboard2 [Allwinner sun7i (A20) CPU], but I can't remember for sure. – capitano666 Nov 11 '16 at 16:32
  • IMO, besides the portable argument, the problem with "I know this works" is that it hides the programmer's intention, relying on an implicit assumption any reader of that code must know to interpret the code. – John Z. Li Feb 14 '18 at 06:37
  • `memset()` is ok to initialize complex data types **as long as you use it to initialize to zero**. You are saying that the correctness of `memset()` depends on the datatype. But this is simply not the case. You can either `memset()` a byte buffer to any byte value, or you can `memset()` an object of any type to `0`. You only get into trouble when you violate both rules at the same time. – cmaster - reinstate monica Mar 08 '20 at 10:10
  • Beside your great hint and to come back to the provided example, there is apparently already undefined behavior since the OP attempt to print indeterminate values. – RobertS supports Monica Cellio Mar 08 '20 at 11:04
  • @cmaster-reinstatemonica : even for initializing to `0` it's not ok. A [pointer with all bits set to `0`](https://stackoverflow.com/questions/27714377) doesn't necessarily represent a null pointer. A [floating point with all bits set to `0`](https://stackoverflow.com/questions/53783149) doesn't necessarily represent `0.0`. Before standardization, even integers with all bits set to `0` didn't necessarily represent the value `0` (due to trap representations, and no exception for all `0` bits). Granted, on the vast majority of systems this won't be an issue, but better be safe than sorry. – Sander De Dycker Mar 09 '20 at 08:12
  • @SanderDeDycker `memset(..., 0, ...)` is just as good/evil as `calloc()`. And you don't advocate against the use of `calloc()`, do you? – cmaster - reinstate monica Mar 09 '20 at 09:49
  • @cmaster-reinstatemonica : your assumption is wrong. – Sander De Dycker Mar 09 '20 at 12:39
  • @SanderDeDycker At least you are consistent, then :-) Myself, I use both `memset(..., 0, ...)` and `calloc()` where appropriate. But I'm usually working on X86 anyways, no exotic platforms that might implement `NULL` with a nonzero bit pattern. I won't doubt that such platforms may exist. Would be quite a braindead platform, though, as C mandates that `NULL` compares equal to `0`. – cmaster - reinstate monica Mar 09 '20 at 12:52
11

gcc provides a good array initialization shortcut

int arr[32] = {[0 ... 10] = 3, [11 ... 31] = 4}

mind the space before and after ...

ffff
  • 2,853
  • 1
  • 25
  • 44
6

Why the division?

memset(arr, -1, sizeof(arr));

Your version, sizeof(arr)/sizeof(int), gives you the number of elements in the array.

Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
  • 3
    Note that `memset()` sets the value of the _bytes_ at the addressed location, not how many "items." You'd want to set the 5 ints worth of bytes to `-1`. Doing so will just happen to set the int values to `-1` as a coincidence of the format. – Jeff Mercado Aug 26 '11 at 09:18
  • 1
    @Jeff: indeed, coincidence, because an int of -1 is usually $FFFFFFFF (assuming 32 bit int and two's complement) and a byte of -1 is $FF. Had he chosen -2 ($FE), it would have become $FEFEFEFE, which is an int of -16843010. – Rudy Velthuis Aug 26 '11 at 11:03
4

You can save yourself some typing by initializing the array directly:

int arr[5] = {-1, -1, -1, -1, -1}; 

That line is shorter than the memset, and it also works.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
1
void * memset ( void * ptr, int value, size_t num );

This function works well on most systems when applied to set char array. It sets the first num BYTES of the block of memory pointed by ptr to the specified value (interpreted as an unsigned char). memset-C++ Reference It operates one byte each time. So it works fine if you assign the second arguments with a int value no more than 0xff.

As for your version, the third arguments is the number of array elements, so you got your output. Actually the truth is you are supposed to assign the third arguments the NUMBER OF BYTES you want.

So the correct version should be like this:

memset (arr, -1, sizeof(arr));
kingo
  • 31
  • 4