Why does "memset(arr, -1, sizeof(arr)/sizeof(int))" not clear an integer array to -1?

60,502

Solution 1

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.

Solution 2

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.

Solution 3

gcc provides a good array initialization shortcut

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

mind the space before and after ...

Solution 4

Why the division?

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

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

Solution 5

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.

Share:
60,502
Ravi Gupta
Author by

Ravi Gupta

Updated on July 09, 2022

Comments

  • Ravi Gupta
    Ravi Gupta almost 2 years

    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
    
    • Thomas Dignan
      Thomas Dignan over 12 years
      might be easier to do this: int arr[5] = {-1};
    • tinman
      tinman over 12 years
      @Tom Dignan: Except that only initialises the first element to -1 and all the rest to 0.
  • Patrick B.
    Patrick B. over 12 years
    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.
  • Jeff Mercado
    Jeff Mercado over 12 years
    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.
  • Ioan Paul Pirau
    Ioan Paul Pirau over 12 years
    You are right Patrick, Thank you.. I changed my answer accordingly
  • Sander De Dycker
    Sander De Dycker over 12 years
    @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.
  • Rudy Velthuis
    Rudy Velthuis over 12 years
    @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.
  • Pascal Cuoq
    Pascal Cuoq over 12 years
    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.
  • Adam Naylor
    Adam Naylor over 12 years
    +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.
  • Sander De Dycker
    Sander De Dycker over 12 years
    @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.
  • Martin Konicek
    Martin Konicek over 11 years
    +1 for array initializer, although it's useful just for few values.
  • capitano666
    capitano666 over 10 years
    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.
  • phuclv
    phuclv over 10 years
    every int whose all four bytes have the same value can use memset, not only 0 and -1
  • Ciro Santilli OurBigBook.com
    Ciro Santilli OurBigBook.com about 8 years
    @LưuVĩnhPhúc but are the representations besides 0 guaranteed? 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.
  • Frederick
    Frederick over 7 years
    @capitano666 - just curious - what processor ("machine") were you using?
  • supercat
    supercat over 7 years
    @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.
  • Sander De Dycker
    Sander De Dycker over 7 years
    @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.
  • supercat
    supercat over 7 years
    @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
    supercat over 7 years
    ...implementations that do not exist and are extremely unlikely to exist in future.
  • capitano666
    capitano666 over 7 years
    @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.
  • John Z. Li
    John Z. Li over 6 years
    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.
  • cmaster - reinstate monica
    cmaster - reinstate monica about 4 years
    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.
  • RobertS supports Monica Cellio
    RobertS supports Monica Cellio about 4 years
    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
    RobertS supports Monica Cellio about 4 years
    One could also abbreviate that and omit the explicit specification of the amount of elements, since the compiler detects the amount of elements by the number of initializations: int arr[] = {-1, -1, -1, -1, -1}; .
  • RobertS supports Monica Cellio
    RobertS supports Monica Cellio about 4 years
    "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.
  • Sander De Dycker
    Sander De Dycker about 4 years
    @cmaster-reinstatemonica : even for initializing to 0 it's not ok. A pointer with all bits set to 0 doesn't necessarily represent a null pointer. A floating point with all bits set to 0 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.
  • cmaster - reinstate monica
    cmaster - reinstate monica about 4 years
    @SanderDeDycker memset(..., 0, ...) is just as good/evil as calloc(). And you don't advocate against the use of calloc(), do you?
  • Sander De Dycker
    Sander De Dycker about 4 years
    @cmaster-reinstatemonica : your assumption is wrong.
  • cmaster - reinstate monica
    cmaster - reinstate monica about 4 years
    @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.