访问数组超出 C 和 C++ 中的限制
Access array beyond the limit in C and C++
int data[8];
data[9] = 1;
C++标准对此有何规定?这是未定义的行为吗?
至少C编译器(gcc -std=c99 -pedantic -W -Wall)没有说什么。
在数组边界之外访问是未定义的行为,来自 c99 草案标准部分 Annex J.2
J.2 未定义行为包括以下几点:
数组下标超出范围,即使对象显然可以通过 给定下标(如左值表达式 a[1][7] 给定声明 int 答[4][5])(6.5.6)。
C++标准草案第5.7
节添加剂运营商第5段说:
当在指针中添加或减去具有整型类型的表达式时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果和原始数组元素的下标之差等于整数表达式。[...]如果指针操作数和结果都指向同一数组对象的元素,或者指向数组对象的最后一个元素,则计算不应产生溢出;否则,行为是未定义的。
为完整起见,第5.2.1
节下标第1段说:
[...]表达式 E1[E2] 与 *((E1)+(E2)) 相同(根据定义)[ 注意:有关 * 和 + 的详细信息,请参见 5.3 和 5.7,有关数组的详细信息,请参见 8.3.4。
需要注意的是,编译器不需要为未定义的行为生成警告(诊断),第 1.4
节中的标准草案C++ 实施合规性第 1 段说:
可诊断规则集包括本标准中的所有句法和语义规则,但包含"不需要诊断"的明确符号或被描述为导致"未定义行为"的规则除外。
是的,这是未定义的行为。
编译器可能会也可能不会警告您注意未定义的行为,即使它能够检测到它。
这被视为未定义的行为。 如果您尝试编译将导致未定义行为的代码,则编译器不需要发出警告,尽管这样做很好。
未定义。它可能是也可能不是无效内存,这使得它变得危险。您可以使用像 valgrind 这样的工具来检测这样的错误访问。
是的,这是未定义的行为。一切都可能发生,它可能有效也可能无效,它可能工作 2 年然后停止工作。这是三个中最危险的:
- 未定义的行为
- 未指定的行为
- 实现定义的行为
你可以检查一下,看看它的其他亲戚:C++程序员应该了解哪些常见的未定义行为?
未定义、未指定和实现定义的行为
C 和 C++ 不检查边界。您尝试达到的值几乎可以是任何东西。它似乎可以在您的编译器上运行,但它不是合法的 C 或 C++,并且不能保证下次运行该程序时它仍然可以工作。
根据 ISO C 标准,访问边界外的数组会导致
未定义的行为:使用不可移植或错误的程序构造或错误数据时的行为,本标准对此没有要求
当您尝试取消引用指向不允许程序访问的内存的指针时,会发生分段错误,并且仅超过数组的末尾可能不会导致这种情况。但它很可能会给你一些不好的价值观。
是的,这是未定义的行为,一些编译器对此发出警告,其他编译器没有,但让我们看看,你的代码会。
查看内联实现[]
操作器。 a[b]
实际上是*(a + b)
.因此,请回到您的代码。
int data[8];
data[9] = 1;
首先,分配堆栈的某些部分并创建指向第一个元素的指针。然后你重写一些数据,这是在你的数组之后,所以你破坏了一些数据。
再举一个例子:
int data[8];
int data2[8] = {};
data[9] = 1;
编译器很可能生成分配一次的代码并创建两个指针作为数组。因此,data[9] = 1;
可以将第二个值data2
设置为 1,但不能保证这一点。
- Mongodb c++驱动程序:如何查询元素的数组
- 将数组的地址分配给变量并删除
- 从C++本机插件更新Vector3数组
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 数组索引的值没有增加
- 将对象数组的引用传递给函数
- 为char数组调整zlib-zpipe
- 2D数组来自文本输入,中间有空格
- std::向量与传递值的动态数组
- 在c++中用vector填充一个简单的动态数组
- 使用strcpy将char数组的元素复制到另一个数组
- 使用指针从C++中的数组中获取最大值
- C++使用整数的压缩数组初始化对象
- 告诉一个 const char 数组,除了编译时 C 样式的字符串外,它不以 '