假设我做了如下事情:
size_t length = 1000;
char* p = malloc(length);
然后我想循环遍历元素,所以最基本的是:
for (size_t i = 0; i < length; ++i) {
p[i] = ...; // or p[length - 1 - i] = ...
}
但也有可能是
char* q = p;
for (size_t i = 0; i < length; ++i) {
*q = ...;
++q;
}
或相反
char* q = p + (length - 1);
for (size_t i = 0; i < length; ++i) {
*q = ...;
--q;
}
我的问题是,如果我想避免i
并执行以下操作:
char* const final = p + (length - 1);
for (char* q = p; q <= final; ++q) {
*q = ...;
}
或相反:
char* const final = p + (length - 1);
for (char* q = final; q >= p; --q) {
*q = ...;
}
似乎在这些循环中出现错误行为的可能性非常小,以避免i
;对于第一个循环,如果p + length == 0
,即我们有一个系统,我们在可能的末尾分配了内存size_t
发生了限制和溢出...对于第二个循环,如果p == 0
,即我们有一个系统,我们在内存的开头分配了内存...在这两种情况下,循环都不会在需要时结束...
也许这些并没有真正发生,但如果这是未定义的行为,那么也许最好用循环i
虽然看起来稍微不太优雅..
编辑:在 Fe2O3 的评论之后,我记得我确实想以不同的方式问它。也就是说,我不想要一个数组char
s,而是某种结构类型的元素数组,因此该结构可能相对较大,大小3000
, 说。那么就足够了p
to be < 3000
为了使第二个循环失败,没有必要将其0
。另外,这也足够了final
为最大尺寸减去3000
... 当然,3000
还可以更大...
TL;DR:递增指针版本可以,但递减指针版本未定义。
C 标准将数组中的指针算术定义为有效,只要结果指针指向 arrar 的元素或指向“末尾的一个”。在这种特殊情况下,您会得到一个无法取消引用的有效指针(这样做是未定义的),但它始终会比指向数组任何元素的任何指针大
6.5.6.8当一个整数类型的表达式与指针相加或相减时,
结果具有指针操作数的类型。如果指针操作数指向一个元素
一个数组对象,并且数组足够大,结果指向从
原始元素,使得结果和原始元素的下标之差
数组元素等于整数表达式。换句话说,如果表达式 P 指向
数组对象的第 i 个元素,表达式 (P)+N(等效于 N+(P))和
(P)-N(其中 N 的值为 n)分别指向第 i+n 个和第 i−n 个元素
数组对象,前提是它们存在。此外,如果表达式 P 指向最后一个
数组对象的元素,表达式 (P)+1 指向最后一个元素
数组对象,如果表达式 Q 指向数组对象的最后一个元素,
表达式 (Q)-1 指向数组对象的最后一个元素。如果两个指针
操作数和结果指向同一个数组对象的元素,或者指向最后一个元素
数组对象的元素,求值不得产生溢出;否则,
行为未定义。如果结果指向数组对象的最后一个元素,则它
不得用作所求值的一元 * 运算符的操作数。
因此,当您递增指针时,当您越过数组末尾时,您将得到这个特殊的“越过末尾”指针,该指针将比指向最后一个元素的指针大,并且循环将终止。然而,使用递减循环,在到达第一个元素后,您将再次递减指针并“下溢”,从而给出未定义的行为。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)