【问题标题】:How memset() works in c++memset() 在 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,在这种情况下他应该使用值初始化。所以他需要数组的大小,而不是数组使用的存储大小。硬编码数组大小正在招致糟糕的一天发生

标签: c++ multidimensional-array memset


【解决方案1】:

你的第一个代码sn-p中的memset调用存在三个问题:

  1. 大小计算不正确。您可以使用3*sizeof(chk[0]) 而不是9*sizeof(chk[0])。但实际上你应该只使用sizeof(chk),因为你有一个局部变量,而不是一个指针,就像使用正式参数一样。

  2. 标准不保证true 的内存表示是位模式1 的假设。在实践中它会成立,但最好直接使用值true 而不是不必要的假设。

  3. 在 C++ 中,只需将变量初始化为零以使其全为零,例如bool chk[3][3] = {};,或使用std::fill 用给定值填充数组,例如fill( &amp;chk[0][0], &amp;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 的示例中所示。
    猜你喜欢
    • 2012-09-02
    • 2011-08-03
    • 1970-01-01
    • 2020-12-02
    • 1970-01-01
    • 2012-05-25
    • 1970-01-01
    • 1970-01-01
    • 2011-11-17
    相关资源
    最近更新 更多