memset() 在 C++ 中的工作原理
Posted
技术标签:
【中文标题】memset() 在 C++ 中的工作原理【英文标题】:How memset() works in c++ 【发布时间】:2018-09-03 16:57:19 【问题描述】:我创建了一个布尔二维数组并像这样使用memset
:
bool chk[3][3];
memset(chk, 1, 9*sizeof(chk[0]));
我使用以下代码块得到了预期的输出(每行有 1 个)
for(int i = 0 ; i < 3; i++)
for(int j = 0; j < 3; j++)
cout<<chk[i][j] <<" ";
cout<<endl;
但是当我尝试操作数组时,我得到了意想不到的结果
然后我尝试了
memset(chk, 1, 9*sizeof(chk[0][0]));
这次一切都很好,得到了我预期的结果(操作后)
你能帮我指出 memset() 中到底发生了什么吗?
【问题讨论】:
sizeof(chk[0]) == sizeof(bool[3]) == 3*sizeof(bool)
。您的程序通过缓冲区溢出表现出未定义的行为。
您系统上的bool
有多大?
如果你确定你总是有一个真正的数组(而不是一个指向动态分配内存的指针),最安全的选择是简单地使用sizeof(chk)
。显然,使用文字 9
很容易导致数组尺寸发生变化(这个问题与类型无关,因此sizeof(chk[0])
中的大小不匹配)。
memset
不是最好的工具,因为每个bool
的每个字节都将设置为一个。修复大小问题并使用int
尝试此操作,您会看到输出类似于 16843009 而不是 1。您可以使用 bool 解决它,因为所有不是 0 的东西都是正确的,但是您做了很多次工作
@Swordfish 因为他不应该使用 memset,除非将它设置为 0,在这种情况下他应该使用值初始化。所以他需要数组的大小,而不是数组使用的存储大小。硬编码数组大小正在招致糟糕的一天发生
【参考方案1】:
你的第一个代码sn-p中的memset
调用存在三个问题:
大小计算不正确。您可以使用3*sizeof(chk[0])
而不是9*sizeof(chk[0])
。但实际上你应该只使用sizeof(chk)
,因为你有一个局部变量,而不是一个指针,就像使用正式参数一样。
标准不保证true
的内存表示是位模式1 的假设。在实践中它会成立,但最好直接使用值true
而不是不必要的假设。
在 C++ 中,只需将变量初始化为零以使其全为零,例如bool chk[3][3] = ;
,或使用std::fill
用给定值填充数组,例如fill( &chk[0][0], &chk[0][0] + 9, true );
。
附录:为了迂腐,在第 1 点有一个假设 bool
是 1 个字节。这也是一个在实践中成立但不受标准保证的假设。很高兴使用std::fill
不是问题。
【讨论】:
零初始化也不会将值设置为 true。 @user2079303:你可以使用std::fill
。要增加整数数组中的值,您可以使用std::iota
。这些是更多类型安全的函数。
+2 填充,如果可以的话。不能保证 bool
是 1 个字节,因此 memset 可能会写出有趣的模式,正如 @user4581301 已经观察到的那样。
是否允许迭代第一个子数组超出其边界,以便迭代兄弟数组?我在 SO 上看到过答案,声称这是 UB。
@user2079303:标准通过sizeof
的要求保证数组是连续的,没有填充。所以是的,没关系。【参考方案2】:
sizeof(chk[0])
是 sizeof(bool[3])
明显不同于 sizeof(chk[0][0])
是 sizeof(bool)
。
使用memset(chk, 1, 9*sizeof(chk[0]));
,您写入超出数组chk
的范围并获得未定义的行为。
【讨论】:
【参考方案3】:我们来看看std::memset
的文档是怎么说的:
如果 count 大于 dest 指向的对象的大小,则行为未定义。
在第一个代码中,9*sizeof(chk[0])
大于chk
的大小,因此程序的行为是未定义的。
memset(chk, 1, sizeof chk)
会更简单,就大小而言显然是正确的。
【讨论】:
考虑到“新用户”这一手,您可能会详细说明chk[0]
的类型和可能大小...考虑到 C 和 C++ 有趣的数组语义,这并不完全明显。【参考方案4】:
sizeof(array)
显然会以字节为单位返回数组的大小。在第一种情况下,您提交给操作员的数组是子数组之一。 C++ 中的多维数组不是。它们是数组的一维数组。执行sizeof(chk)
评估整个数组的大小并将其除以sizeof(chk[0][0])
以获得元素数量。不要使用memset
,因为如果会对布尔的二进制表示做一些奇怪的事情,请使用std::fill
。
【讨论】:
"执行 sizeof(chk) 来评估整个数组的大小并将其除以 sizeof(chk[0][0]) 以获得元素的数量。"我发现这具有误导性,因为问题是关于memset()
,它采用字节数而不是元素数。
@Swordfish memset 是错误的工具,正如 Swift 指出的那样;元素的数量可用于填充,如 Alf 的示例中所示。以上是关于memset() 在 C++ 中的工作原理的主要内容,如果未能解决你的问题,请参考以下文章