c - 动态分配内存上指针算法的未定义行为
问题描述
我可能误解了这一点,但是 c99 规范是否会阻止对动态分配的内存进行任何形式的指针运算?
从 6.5.6p7...
出于这些运算符的目的,指向不是数组元素的对象的指针与指向长度为 1 且对象类型作为其元素类型的数组的第一个元素的指针的行为相同。
...指向不在数组中的对象的指针被视为指向一个包含 1 项的数组(使用运算符 + 和 - 时)。然后在这个片段中:
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)
做无效的取消引用。
解决方案
从C99,7.20.3 - 内存管理功能(强调我的):
如果分配成功,则返回的指针经过适当对齐,以便可以将其分配给指向任何类型对象的指针,然后用于访问已分配空间中的此类对象或此类对象的数组(直到空间被显式释放) .
这意味着分配的内存可以作为char
(根据您的示例)的数组访问,因此指针算术定义明确。
推荐阅读
- bash - Bash:如何使用 for 循环创建映射?
- ios - 使用 GPUImage2 过滤视频流
- ios - 如何使用 Firebase 确保我的代码在 Swift 中按顺序运行?
- php - 如何为 DB::raw 设置绑定?
- react-native - 本地主机上的重定向 url
- arrays - swift中的异构集合文字
- r - 使用 st_distance 计算两组点之间的所有距离
- reactjs - AutocompleteInput 是否可以重置?
- sql-server - 在 modify() 方法中提供 xml 元素值
- python - findall 中的正则表达式与计数中的正则表达式