提问人:Sasha 提问时间:10/7/2023 最后编辑:Sasha 更新时间:10/8/2023 访问量:93
初始或末端 malloc 缓冲液可能吗?
initial or terminal malloc buffer possible?
问:
假设我执行以下操作:
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的评论之后,我记得我确实想问一点不同。也就是说,我想要的不是 s 的数组,而是某种结构类型的元素数组,因此结构体可能相对较大,大小为 ,比如说。那么第二个循环失败就足够了,没有必要。此外,达到最大尺寸减去就足够了......当然,可以更大......char
3000
p
< 3000
0
final
3000
3000
答:
TL;DR:递增的指针版本是可以的,但递减的指针版本是不确定的。
C 标准将数组中的指针算术定义为有效,只要生成的指针指向 arrar 的元素或指向“一个过去的末尾”。在这种特殊情况下,你会得到一个有效的指针,该指针不能被取消引用(这是未定义的),但它将始终比指向数组任何元素的任何指针进行比较
6.5.6.8 当将具有整数类型的表达式添加到指针或从指针中减去时, result 具有指针操作数的类型。如果指针操作数指向 一个 Array 对象,并且数组足够大,则结果指向 原始元素使得结果和原始元素的下标的差异 数组元素等于整数表达式。换言之,如果表达式 P 指向 数组对象的第 i 个元素,表达式 (P)+N(等效地,N+(P))和 (P)-N(其中 N 的值为 n)分别指向 数组对象,前提是它们存在。此外,如果表达式 P 指向最后一个 元素,则表达式 (P)+1 指向 array 对象,如果表达式 Q 指向数组对象的最后一个元素, 表达式 (Q)-1 指向数组对象的最后一个元素。如果两个指针 操作数和结果指向同一数组对象的元素,或指向最后一个元素 元素,则计算不得产生溢出;否则, 行为未定义。如果结果指向数组对象的最后一个元素,则 不得用作被计算的一元 * 运算符的操作数。
因此,当你递增指针时,当你超过数组的末尾时,你会得到这个特殊的“一个超过末尾”的指针,该指针将比指向最后一个元素的指针更大,并且循环将终止。但是,在递减循环中,在到达第一个元素后,您将再次递减指针并“下溢”,从而产生未定义的行为。
评论
p + (length - 1)
final
length == 0
q < final
final = p + length;
length != 0
char
总结一下人们所说的话(谢谢!),以下几点应该始终有效(我认为):
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 = ...;
}
评论
for (type_t* r = q; r > p; ) { *--r=
r == p
r
0
?哈哈)并坚持循环 :-)length >= 1
do ... while
r-- > p
r--
r
p
r--
r
p
r--
r
r--
r
char* p = malloc(10); --p; ++p;
char* p = malloc(10);
char* p = malloc(10); p += 10; p -= 10;
评论
0
在大多数实现中,等同于 或 。这是分配失败的“特殊迹象”。因此,它不能同时用于指示成功分配。在另一端,“堆”边界不能渗入位于最高地址的边界。换句话说,这不是一个问题......(void*)0
NULL
stack
p + length
根据标准,始终是正确的。对于第二种情况,请使用do ... while(q-- > p);
for (char* q = final +1; q-- > p; )
q
p
p + length
作为指针总是正确的(例如,对于指针比较)......如果取消引用,则不正确:无效!*(p + length)