27

为什么是以下程序的输出84215045

int grid[110];
int main()
{
    memset(grid, 5, 100 * sizeof(int));
    printf("%d", grid[0]);
    return 0;
}
4

9 回答 9

49

memset将目标缓冲区的每个字节设置为指定值。在您的系统上,anint是四个字节,在调用memset. 因此,grid[0]具有十进制值0x05050505(十六进制)84215045

一些平台提供了替代 API 来memset将更广泛的模式写入目标缓冲区;例如,在 OS X 或 iOS 上,您可以使用:

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

获得您似乎期望的行为。你的目标是什么平台?

在 C++ 中,您应该只使用std::fill_n

std::fill_n(grid, 100, 5);
于 2011-08-17T23:00:39.147 回答
12
memset(grid, 5, 100 * sizeof(int));

您将 400 字节设置为值,从 开始(char*)grid和结束(这里需要强制转换,因为处理字节,而指针算术处理.(char*)grid + (100 * sizeof(int))5memsetobjects

84215045十六进制是0x05050505;因为int(在您的平台/编译器/等上)由四个字节表示,所以当您打印它时,您会得到“四个五”。

于 2011-08-17T23:00:19.117 回答
8

memset是关于设置字节,而不是值。在 C++ 中设置数组值的众多方法之一是std::fill_n

std::fill_n(grid, 100, 5);
于 2011-08-17T23:19:36.503 回答
6

不要使用 memset。

您将[]内存的每个字节设置为值 5。每个 int 为 4 个字节长[5][5][5][5],编译器将其正确解释为 5*256*256*256 + 5*256*256 + 5*256 + 5 = 84215045。相反,使用 for 循环,它也不需要 sizeof()。一般来说, sizeof() 意味着你正在做一些艰难的事情。

for(int i=0; i<110; ++i)
    grid[i] = 5;
于 2011-08-17T23:02:27.743 回答
3

好吧,memset使用选定的值写入字节。因此 int 看起来像这样:

00000101 00000101 00000101 00000101

然后将其解释为 84215045。

于 2011-08-17T23:01:16.590 回答
2

你实际上并没有说你想让你的程序做什么。

假设您要将前 100 个元素中的每一个都设置grid为 5(并忽略100110差异),只需执行以下操作:

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

我了解您担心速度,但您的担心可能是错误的。一方面,memset()可能会被优化,因此比简单的循环更快。另一方面,优化可能包括一次写入多个字节,这就是这个循环所做的。另一方面,memset()无论如何都是一个循环;显式编写循环而不是将其埋在函数调用中并不会改变这一点。另一方面,即使循环很慢,也可能无关紧要。专注于编写清晰的代码,如果实际测量表明存在严重的性能问题,则考虑对其进行优化。

你写问题所花费的时间比你的计算机设置所花费的时间要多几个数量级grid

最后,在我手忙脚乱(为时已晚!)之前,memset()如果它没有按照您的意愿行事,那么速度有多快并不重要。(完全不设置grid甚至更快!)

于 2011-08-17T23:31:42.450 回答
1

如果你man memset在 shell 上输入,它会告诉你

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

一个简单的英语解释是,它用每个字节填充一个b长度的字节字符串lenvalue c

对于你的情况,

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

由于sizeof(int)==4,因此上面的代码片段看起来像:

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

或者

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

它将打印出84215045

但在大多数 C 代码中,我们希望将一块内存块初始化为零。

  • char输入 -->\0NUL
  • int输入-->0
  • float输入-->0.0f
  • double输入-->0.0
  • 指针类型 -->nullptr

gccclang等现代编译器可以自动为您处理好这个问题。

// 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]);
}

但请注意,C ISO 委员会并没有强加这样的定义,它是特定于编译器的。

于 2018-02-01T06:08:37.210 回答
0

由于 memset 写入字节,我通常使用它将一个 int 数组设置为零,例如:

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

或者您可以使用它来设置 char 数组,因为 char 正是一个字节:

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

更重要的是,一个 int 数组也可以通过 memset 设置为 -1:

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

这是因为 -1 在 int 中是 0xffffffff,在 char(一个字节)中是 0xff。

于 2011-08-18T02:16:18.467 回答
0

此代码已经过测试。这是一种将“整数”数组设置为 0 到 255 之间的值的方法。

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

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

memset(MinColCost,0xff,(Len+1)*sizeof(int));
于 2012-09-11T15:19:34.900 回答