Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

initial or terminal malloc buffer possible?

Suppose I do something as follows:

size_t length = 1000;
char* p = malloc(length);

and then I want to loop over the elements, so most basic would be:

for (size_t i = 0; i < length; ++i) {
  p[i] = ...; // or p[length - 1 - i] = ...
}

but also possible is

char* q = p;
for (size_t i = 0; i < length; ++i) {
  *q = ...;
  ++q;
}

or in reverse

char* q = p + (length - 1);
for (size_t i = 0; i < length; ++i) {
  *q = ...;
  --q;
}

My question is, what if I want to avoid the i and do something as follows:

char* const final = p + (length - 1);
for (char* q = p; q <= final; ++q) {
  *q = ...;
}

or in reverse:

char* const final = p + (length - 1);
for (char* q = final; q >= p; --q) {
  *q = ...;
}

It seems that there is a very tiny chance of erroneous behavior in those loops avoiding i; for the first loop, what if p + length == 0, i.e. we have a system where we were allocated memory just at the very end of the possible size_t limit and overflow happened... For the second loop, what if p == 0, i.e. we have a system where we were allocated memory just at the beginning of memory... In both these scenarios the loop will not end when needed...

Probably those do not really happen, but if this is undefined behavior then maybe it is better to loop with the i although it looks slightly less elegant..


Edit: Following Fe2O3's comment, I recalled that indeed I wanted to ask it a bit differently. Namely, I would like not an array of chars, but an array of elements of some struct type, so the struct is potentially relatively big, of size 3000, say. Then it is enough for p to be < 3000 in order for the second loop to fail, it is not necessary for it to be 0. Also, it is enough for final to be at the maximum size minus 3000... Of course, 3000 can be even bigger...

like image 943
Sasha Avatar asked Sep 08 '26 18:09

Sasha


1 Answers

TL;DR: The incrementing pointer version is ok, but the decrementing one is undefined.

The C standard defines pointer arithmetic in an array to be valid as long as the resulting pointer points at an element of the arrar or it points to "one past the end". In that special case you get a valid pointer that can't be dereferenced (it is undefined to do so), but that will always compare as greater than any pointer to any element of the array

6.5.6.8 When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i+n-th and i−n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.

So when you're incrementing the pointer, when you get past the end of the array, you'll get this special "one past the end" pointer that will compare as greater than the pointer to the last element and the loop will terminate. With the decrementing loop, however, after the first element is reached, you'l decrement the pointer again and "underflow" giving undefined behavior.

like image 104
Chris Dodd Avatar answered Sep 10 '26 15:09

Chris Dodd



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!