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

从0偏移量写入多维数组是否为UB?C/C++合法性求证

二维数组跨子数组访问的合法性分析(C/C++标准解读)
#include "stdio.h"

#define N 2
#define M 2

int main(void)
{
    int two_d[N][M];
    for(size_t i = 0; i < N*M; ++i) {
        two_d[0][i] = i;  // <---- 注意此行!
    }
    for(size_t i = 0; i < N; ++i) {
        for(size_t j = 0; j < M; ++j) {
            printf("%d\n", two_d[i][j]);
        }
    }
    return 0;
}

这段代码来自某知名实际项目,核心争议点在于two_d[0][i]当i >= M时的访问行为,存在两种观点:

  • 观点1:二维数组内存连续布局,整体访问未越界,合法
  • 观点2:访问了第一个子数组的边界外内存,属于未定义行为(UB)

本地编译及Godbolt测试中,C/C++编译器开启优化后均能正常运行,但需依据官方标准判断合法性。

1. C语言中的合法性判断

结论:属于未定义行为

根据C17标准§6.5.2.1(数组下标):

下标运算符[]的定义是E1[E2]等价于(*((E1)+(E2)))。对于数组类型的表达式E1,其值是指向数组首元素的指针。当E2的值超出数组的有效下标范围时,指针运算和后续的解引用操作属于未定义行为。

代码中two_d[0]是长度为M的一维数组,当i >= M时,two_d[0][i]等价于*(two_d[0] + i),此时two_d[0] + i指向第一个子数组的边界之外。尽管二维数组内存整体连续,但C标准并未允许通过单个子数组的指针访问其他子数组的元素。

同时,C17标准§6.2.5(类型)明确多维数组是“数组的数组”,每个子数组都是独立的数组对象,跨子数组的下标访问超出单个子数组的有效范围,触发未定义行为。

2. C++语言中的合法性判断

结论:属于未定义行为

根据C++20标准§7.6.1.2(数组下标):

表达式E1[E2]等价于*((E1)+(E2)),其中E1是数组类型的表达式,E2是整数类型。如果E2的值不在数组的有效下标范围内(即0 <= E2 < 数组长度),则行为未定义。

two_d[0]是长度为M的int[M]数组,当i >= M时,two_d[0][i]的下标超出该子数组的有效范围。无论二维数组内存是否连续,这种访问都违反了数组下标必须在有效范围内的要求,属于未定义行为。

此外,C++标准中多维数组同样是“数组的数组”,每个子数组作为独立对象,其指针的运算和解引用不能超出自身边界,即使后续内存属于同一多维数组的其他部分。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 03:01:12