当前位置: 首页 > 知识库问答 >
问题:

复制带有“memcpy”的2D数组在技术上是不确定的行为吗?

芮明知
2023-03-14

在最近这个问题的注释中出现了一个有趣的讨论:现在,尽管有C语言,讨论已经转移到C++标准规定了什么,即使用std::memcpy这样的函数访问多维数组元素时,什么构成未定义的行为。

首先,下面是这个问题的代码,转换为C++,并尽可能使用const:

#include <iostream>
#include <cstring>

void print(const int arr[][3], int n)
{
    for (int r = 0; r < 3; ++r) {
        for (int c = 0; c < n; ++c) {
            std::cout << arr[r][c] << " ";
        }
        std::cout << std::endl;
    }
}

int main()
{
    const int arr[3][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };
    int arr_copy[3][3];
    print(arr, 3);
    std::memcpy(arr_copy, arr, sizeof arr);
    print(arr_copy, 3);
    return 0;
}

问题出在调用std::memcpy:时:arr参数将产生(通过衰减)指向第一个子数组int[3]的指针,因此,根据讨论的一方(由Ted Lyngmo牵头),当memcpy函数访问该子数组第三个元素以外的数据时,存在形式上未定义的行为(同样也适用于目标arr_copy)。

然而,争论的另一面(MediocrePegritable1和我都赞同)使用的原理是,根据定义,每个2D数组都将占用连续内存,并且由于memcpy的参数只是指向这些位置的void*指针(第三个size参数有效),所以这里不可能有UB。

这里总结了一些与辩论最相关的评论,以防在最初的问题上出现任何“清理”(我用粗体字强调):

我不认为这里有任何出界的地方。就像memcpy适用于int数组一样,它也适用于int[3]数组,两者应该是连续的(但我不能100%确定)。-平庸素食1

当从arr[0][3]复制第一个字节时,会发生越界访问。我从来没有见过它真正失败,但是,在C++中,它有UB。-泰德·林格莫

但是memcpy函数/call并不执行任何数组索引--它只得到两个void*指针,并将内存从一个复制到另一个。--阿德里安·摩尔

我不能肯定这在C中是否重要,在C++中则不然。您将获得一个指向第一个int[3]的指针,任何超出其范围的访问都具有ub。我在C++标准中没有发现任何例外。-泰德·林格莫

是否有任何C++语言--律师可以解决这个问题--最好用C++标准中的适当引用?

另外,从C标准中引用相关的内容可能会有所帮助--尤其是在两种语言标准不同的情况下--所以我在这个问题中包含了C标记。

共有1个答案

戚飞
2023-03-14

std::memcpy(arr_copy,arr,sizeof arr);(您的示例)定义良好。

std::memcpy(arr_copy,arr[0],sizeof arr);则会导致未定义的行为。

多维数组是数组的一维数组。据我所知,与真正的1D数组(即具有非数组类型元素的数组)相比,它们没有得到太多(如果有的话)特殊处理。

int a[3] = {1,2,3}, b[3];
std::memcpy(b, a, sizeof(int) * 3);

元素类型不影响此示例的有效性。如果使用2D数组,则元素类型将变为int[N]而不是int,但有效性不受影响。

现在,考虑一个不同的例子:

int a[2][2] = {{1,2},{3,4}}, b[4];
std::memcpy(b, a[0], sizeof(int) * 4);
//             ^~~~

这会导致UB,因为memcpy被赋予指向a[0]第一个元素的指针,所以它只能访问a[0](a[0][i])的元素,而不能访问a[j][i]

 类似资料:
  • 问题内容: 我有一个二维数组,称为int类型的矩阵,我想用一种方法将其复制到局部变量,以便我可以对其进行编辑 什么是复制阵列的最佳方法,我遇到了一些麻烦 例如 问题答案: 有两种复制数组的好方法是使用clone和。 这是在2D情况下如何使用克隆的方法: 对于System.arraycopy(),你可以使用: 我没有基准,但是我可以用我的2美分打赌,它们比你自己做的更快,更不容易出错。特别是,它是用

  • 我使用HashMap来存储每个元素的出现,然后遍历哈希图以获取重复的元素,但这个解决方案感觉不太对劲。 Firecode.io中的问题陈述: 编写一个方法duplicate来查找数组中重复的元素。该方法应该返回一个字符串中重复整数的列表,其中的元素按升序排序(如下所示)。 -- -- 注意:您可以使用 toString() 方法返回大多数数据结构的标准字符串表示形式,并使用 Arrays.sort

  • 我知道要在数组中查找值是否存在,我可以使用indexOf,但如何使用对象数组呢?

  • 我试图建立一个方法,将排序一个二维数组的双打按列。基于所提供的规范,此方法也不应该采用长度不等的行的粗糙数组。我正在使用双[][]mdarray={{3.0, 4.0, 1.0, 8.0},{13.0, 2.0, 12.0, 9.0}测试这个 使用打印方法时,应将其显示为 3.0, 2.0, 1.0, 8.0, 13.0, 4.0, 12.0, 9.0, 使用单独的打印方法输出结果时,数组似乎没有

  • 我正在寻找性能最友好的方法来检查数组中的所有值是否为null,或者是否至少有一个元素具有其他类型。 也就是说,我需要一个方法,它根据传递的数组返回布尔值 例如:

  • 问题内容: 有没有一种方法可以定义次数,而不必总是遍历数组? 例如,在下面,我希望列表项显示5次,并假设等于5,并且增加数字,因此每个列表项都按1、2、3、4、5递增 所需结果: 问题答案: 较新版本的AngularJS(> = 1.3.0)允许您仅使用变量(无需功能)来执行此操作: 在首次提出问题时这是不可能的。感谢@Nikhil Nambiar从下面的回答中获得此更新 原创(5/29/2013