You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用memcpy复制二维数组在C/C++中是否属于技术上的未定义行为?

使用std::memcpy复制多维数组的行为界定争议

近期相关问题的评论区产生了一个有趣的讨论:尽管原问题涉及的是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也存在同样问题)。

而包括mediocrevegetable1在内的反对方则持如下逻辑:根据定义,每个二维数组的内存空间都是连续的,且传入memcpy的参数仅为指向对应位置的void*指针(第三个size参数也合法),因此这里不存在未定义行为。

以下是本次争议相关的核心评论汇总:

我不认为这里存在越界访问。就像memcpy可以正常复制int类型数组一样,它也适用于int [3]类型的数组,二者的内存都是连续的(不过我不能百分百确定)。—— mediocrevegetable1

越界访问出现在你复制arr[0][3]的第一个字节时。我从没见过这种写法实际运行出错,但在C++中这确实属于UB。—— Ted Lyngmo

但memcpy函数/调用本身并没有做任何数组索引操作,它只是接收两个void*指针,然后将内存从一个地址复制到另一个地址。—— Adrian Mole

我不确定这在C中是否有影响,但在C中确实有问题。你得到的是指向第一个int[3]的指针,任何超出其范围的访问都属于UB。*我在C标准中没有找到任何相关的例外规定。*—— Ted Lyngmo

我不认为arr[0][3]的说法成立。按照这个逻辑,用memcpy复制int数组的第二个int元素也会是UB了。int [3]只是arr的元素类型,arr整体的字节边界应该是sizeof (int [3]) * 3。不过我可能漏看了什么:/ —— mediocrevegetable1

有没有C语言律师可以解决这个问题?最好能附上C标准的相关引用佐证。此外,来自C标准的相关引用也会很有帮助——尤其是如果两种语言的标准在这一点上存在差异的话,因此该问题也添加了C标签。


内容的提问来源于stack exchange,提问作者Adrian Mole

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 02:57:01