初始或终端malloc缓冲区可能吗?

wfsdck30  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(69)

假设我做如下事情:

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循环,尽管它看起来稍微不那么优雅。
编辑:在Fe 2 O3的评论之后,我回忆说,我确实想问一个不同的问题。也就是说,我不想要一个char s的数组,而是一个由某种结构类型的元素组成的数组,所以这个结构可能相对较大,比如说,大小为3000。那么p< 3000就足以使第二个循环失败,它不一定是0。此外,final的最大大小减去3000就足够了。当然,3000可以更大...

nhaq1z21

nhaq1z211#

TL;DR:递增指针版本是可以的,但递减指针版本是未定义的。
C标准定义了数组中的指针算法,只要结果指针指向数组的一个元素或它指向“结束后的一个”,它就有效。在这种特殊情况下,你得到一个有效的指针,它不能被解引用(这样做是未定义的),但它总是比指向数组中任何元素的指针都大

6.5.6.8当一个整数类型的表达式与指针相加或相减时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果和原始数组元素的下标之差等于整数表达式。换句话说,如果表达式P指向数组对象的第i个元素,则表达式(P)+N(等价地,N+(P))和(P)-N(其中N的值为n)分别指向数组对象的第i+ n个元素和第i-n个元素,前提是它们存在。此外,如果表达式P指向数组对象的最后一个元素,则表达式(P)+1指向数组对象的最后一个元素之后的一个元素,如果表达式Q指向数组对象的最后一个元素之后的一个元素,则表达式(Q)-1指向数组对象的最后一个元素。如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象最后一个元素之后的元素,则计算不应产生溢出;否则,行为是未定义的。如果结果指向数组对象的最后一个元素之后的一个元素,则不应将其用作计算的一元 * 运算符的操作数。

所以当你递增指针时,当你越过数组的末尾时,你会得到这个特殊的“一个过去的末尾”指针,它将比指向最后一个元素的指针大,循环将终止。然而,使用递减循环,在到达第一个元素后,您将再次递减指针并“下溢”,从而产生未定义的行为。

qjp7pelc

qjp7pelc2#

”众人纷纷说道。),以下应该总是工作(我认为):

size_t length = ...;
type_t* p = malloc(length * sizeof(type_t));
type_t* const q = p + length;

/* looping incrementally */
for (type_t* r = p; r < q; ++r) {
  *r = ...;
}

/* looping decrementally */
for (type_t* r = q; r > p;) {
  *--r = ...;
}

相关问题