【发布时间】:2019-06-25 00:28:56
【问题描述】:
我可能误解了这一点,但是 c99 规范是否禁止在动态分配的内存上进行任何形式的指针运算?
从 6.5.6p7...
就这些运算符而言,指向不是数组元素的对象的指针与指向长度为 1 且对象类型作为其元素类型的数组的第一个元素的指针的行为相同。
... 指向不在数组中的对象的指针被视为指向包含 1 项的数组(使用运算符 + 和 - 时)。然后在这个sn-p中:
char *make_array (void) {
char *p = malloc(2*sizeof(*p));
p[0] = 1; // valid
p[1] = 2; // invalid ?
return p;
}
...第二个下标p[1] 无效?由于p 指向不在数组中的对象,因此它被视为指向包含一项的数组中的对象,然后从 6.5.6p8...
当一个整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果和原始数组元素的下标之差等于整数表达式。换句话说,如果表达式 P 指向数组对象的第 i 个元素,则表达式 (P)+N(等效于 N+(P))和 (P)-N(其中 N 的值为 n)指向分别到数组对象的第 i+n 个和第 i-n 个元素,前提是它们存在。此外,如果表达式 P 指向数组对象的最后一个元素,则表达式 (P)+1 指向数组对象的最后一个元素,如果表达式 Q 指向数组对象的最后一个元素,则表达式 (Q)-1 指向数组对象的最后一个元素。如果指针操作数和结果都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,则计算不应产生溢出;否则,行为未定义。如果结果指向数组对象的最后一个元素,则不应将其用作计算的一元 * 运算符的操作数。
...我们有未定义的行为,因为我们取消引用超出了数组边界(暗示长度为 1)。
编辑:
好的,为了澄清更多让我感到困惑的地方,让我们一步一步来:
1.) p[1] 被定义为表示*(p+1)。
2.) p 指向一个不在数组内的对象,因此它被视为指向长度为 1 的数组内的一个对象,以便评估 p+1。
3.) p+1 产生一个指针 1 越过 p 暗示指向的数组。
4.) *(p+1) 执行无效取消引用。
【问题讨论】:
-
“因为我们取消引用超出了数组绑定”,但
p不是 数组。 -
我知道不是;我在问题中说明了这一点。但是这里是否有一个隐含的数组,它的界限被越过了?它说 p 被视为指向数组中的一个对象。
-
请注意,在 7.22.3.4p2
The malloc function allocates space for an object whose size is specified by size and whose value is indeterminate.。分配的空间被视为一个对象。然后获取对象指针并将其隐式转换为char *。
标签: c language-lawyer c99 pointer-arithmetic