29

Why is the output of the following program 84215045?

int grid[110];
int main()
{
    memset(grid, 5, 100 * sizeof(int));
    printf("%d", grid[0]);
    return 0;
}
Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
Ahmad
  • 309
  • 1
  • 3
  • 4

9 Answers9

51

memset sets each byte of the destination buffer to the specified value. On your system, an int is four bytes, each of which is 5 after the call to memset. Thus, grid[0] has the value 0x05050505 (hexadecimal), which is 84215045 in decimal.

Some platforms provide alternative APIs to memset that write wider patterns to the destination buffer; for example, on OS X or iOS, you could use:

int pattern = 5;
memset_pattern4(grid, &pattern, sizeof grid);

to get the behavior that you seem to expect. What platform are you targeting?

In C++, you should just use std::fill_n:

std::fill_n(grid, 100, 5);
Stephen Canon
  • 103,815
  • 19
  • 183
  • 269
13
memset(grid, 5, 100 * sizeof(int));

You are setting 400 bytes, starting at (char*)grid and ending at (char*)grid + (100 * sizeof(int)), to the value 5 (the casts are necessary here because memset deals in bytes, whereas pointer arithmetic deals in objects.

84215045 in hex is 0x05050505; since int (on your platform/compiler/etc.) is represented by four bytes, when you print it, you get "four fives."

James McNellis
  • 348,265
  • 75
  • 913
  • 977
8

memset is about setting bytes, not values. One of the many ways to set array values in C++ is std::fill_n:

std::fill_n(grid, 100, 5);
MSN
  • 53,214
  • 7
  • 75
  • 105
  • this function is faster than looping for all elements ?? – Ahmad Aug 17 '11 at 23:21
  • @Ahmad: That function probably does loop over all elements. – Keith Thompson Aug 17 '11 at 23:43
  • 2
    A good compiler will convert both the for loop and `std::fill_n` into either an optimized code sequence that uses wide aligned stores (probably vectors) or a library call that is known to be fast on the target platform. – Stephen Canon Aug 17 '11 at 23:46
6

Don't use memset.

You set each byte [] of the memory to the value of 5. Each int is 4 bytes long [5][5][5][5], which the compiler correctly interprets as 5*256*256*256 + 5*256*256 + 5*256 + 5 = 84215045. Instead, use a for loop, which also doesn't require sizeof(). In general, sizeof() means you're doing something the hard way.

for(int i=0; i<110; ++i)
    grid[i] = 5;
Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
  • i just thought that memset is faster :D – Ahmad Aug 17 '11 at 23:16
  • The backend of `memset` basically just does this. –  Aug 17 '11 at 23:20
  • @Ahmad, theoretically it might be slightly faster. In reality, memset makes your program crash. – Mooing Duck Aug 17 '11 at 23:23
  • 1
    @Mooing Duck: how does memset make your program crash, exactly? – Stephen Canon Aug 17 '11 at 23:25
  • Another reason is for objects where being set to zero is an invalid mistake. memset will happily make those objects crash. A for loop will tell you at compile time. – Mooing Duck Aug 17 '11 at 23:28
  • memset is also easy to misuse, causing too many/few values to be overwritten, whereas a for loop is less error prone. – Mooing Duck Aug 17 '11 at 23:28
  • 1
    Actually, for the specific case of array initialization, I would argue that `memset` is easier to get right, since you can simply use `sizeof array`. That way, if you change the size of your array in the future, the initialization is automatically kept in sync. – Stephen Canon Aug 17 '11 at 23:32
  • @Stephen i think in the Scope of arrays it's fine to use memset you are right about that .. but the idea is that it's easy to bug the code – Ahmad Aug 17 '11 at 23:34
  • @Stephen Realistically I would use a container over a c-array anyway. – Mooing Duck Aug 17 '11 at 23:36
  • 2
    Of course, if you're writing C++, this should be a container and `std::fill`. – Stephen Canon Aug 17 '11 at 23:36
3

Well, the memset writes bytes, with the selected value. Therefore an int will look something like this:

00000101 00000101 00000101 00000101

Which is then interpreted as 84215045.

Šimon Tóth
  • 35,456
  • 20
  • 106
  • 151
2

You haven't actually said what you want your program to do.

Assuming that you want to set each of the first 100 elements of grid to 5 (and ignoring the 100 vs. 110 discrepancy), just do this:

for (int i = 0; i < 100; i ++) {
    grid[i] = 5;
}

I understand that you're concerned about speed, but your concern is probably misplaced. On the one hand, memset() is likely to be optimized and therefore faster than a simple loop. On the other hand, the optimization is likely to consist of writing more than one byte at a time, which is what this loop does. On the other other hand, memset() is a loop anyway; writing the loop explicitly rather than burying it in a function call doesn't change that. On the other other other hand, even if the loop is slow, it's not likely to matter; concentrate on writing clear code, and think about optimizing it if actual measurements indicate that there's a significant performance issue.

You've spent many orders of magnitude more time writing the question than your computer will spend setting grid.

Finally, before I run out of hands (too late!), it doesn't matter how fast memset() is if it doesn't do what you want. (Not setting grid at all is even faster!)

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
1

If you type man memset on your shell, it tells you that

void * memset(void *b, int c, size_t len)

A plain English explanation of this would be, it fills a byte string b of length len with each byte a value c.

For your case,

memset(grid, 5, 100 * sizeof(int));

Since sizeof(int)==4, thus the above code pieces looked like:

for (int i=0; i<100; i++)
    grid[i]=0x05050505;

OR

char *grid2 = (char*)grid;
for (int i=0; i<100*sizeof(int); i++)
    grid2[i]=0x05;

It would print out 84215045

But in most C code, we want to initialize a piece of memory block to value zero.

  • char type --> \0 or NUL
  • int type --> 0
  • float type --> 0.0f
  • double type --> 0.0
  • pointer type --> nullptr

And either gcc or clang etc. modern compilers can take well care of this for you automatically.

// variadic length array (VLA) introduced in C99
int len = 20;
char carr[len];
int iarr[len];
float farr[len];
double darr[len];
memset(carr, 0, sizeof(char)*len);
memset(iarr, 0, sizeof(int)*len);
memset(farr, 0, sizeof(float)*len);
memset(darr, 0, sizeof(double)*len);
for (int i=0; i<len; i++)
{
    printf("%2d: %c\n", i, carr[i]);
    printf("%2d: %i\n", i, iarr[i]);
    printf("%2d: %f\n", i, farr[i]);
    printf("%2d: %lf\n", i, darr[i]);
}

But be aware, C ISO Committee does not imposed such definitions, it is compiler-specific.

x86_64
  • 95
  • 1
  • 10
0

This code has been tested. Here is a way to memset an "Integer" array to a value between 0 to 255.

MinColCost=new unsigned char[(Len+1) * sizeof(int)];

memset(MinColCost,0x5,(Len+1)*sizeof(int));

memset(MinColCost,0xff,(Len+1)*sizeof(int));
Bo Persson
  • 90,663
  • 31
  • 146
  • 203
Frank
  • 1,406
  • 2
  • 16
  • 42
0

Since the memset writes bytes,I usually use it to set an int array to zero like:

int a[100];
memset(a,0,sizeof(a));

or you can use it to set a char array,since a char is exactly a byte:

char a[100];
memset(a,'*',sizeof(a));

what's more,an int array can also be set to -1 by memset:

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

This is because -1 is 0xffffffff in int,and is 0xff in char(a byte).

bigeast
  • 627
  • 5
  • 14