简体   繁体   中英

Why is memset() incorrectly initializing int?

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;
}

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);
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."

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);

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;

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.

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!)

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.

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));

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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM