Why is memset() incorrectly initializing int?

▼魔方 西西 提交于 2019-11-26 09:09:57

问题


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

回答1:


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



回答2:


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




回答3:


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



回答4:


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;



回答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.




回答6:


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




回答7:


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.




回答8:


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




回答9:


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


来源:https://stackoverflow.com/questions/7100529/why-is-memset-incorrectly-initializing-int

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!