C has size_t. Use it.
(And because C doesn't mandate correct handling of benign undefined behavior, you still have a problem if you `return ptr-orig_ptr` as a size_t offset (rather than returning the final ptr directly), because pointer subtraction is specified as producing ptrdiff_t (rather than size_t), which can 'overflow' for large arrays, despite that it's immediatedly converted back to a correct value of size_t.)
The problems here are about using integers that are too narrow and not properly doing arithmetic to prevent overflow from impacting the result.
Isn't this article a counterexample to that? Where using signed instead of unsigned actually does result in a loss of functionality?
Moreover I don't see how you deny that using signed would lose functionality in this case—it's pretty undeniable that it gives the wrong answer in cases where unsigned would give the correct answer; the code is right in the article and you can test it out. This is true irrespective of any other cases that neither might handle correctly (assuming you believe any exist, but see my previous paragraph).
Moreover, it is trivial to convert from a 32-bit signed or unsigned type to a 64-bit int, so you are not constrained by the size type of Java.
Casts from int to pointer should be explicit.
We are enamoured with programmer convenience at the expense of the safety of our systems. It’s unprofessional and we should all aim to fix it.
char array[60000]; // 5KB left for code and stack if not segmented
size_t i = 40000;
size_t j = 50000;
size_t mid = (i+j)/2; // should be 45000
// i+j = (size_t)90000 = 24464
// mid = 24464/2 = 12232 != 45000
Larger integers make the necessary array size bigger, but don't change the overall issue. ['a','b','c'].indexof('b') == 1 // found - return index
['a','b','c'].indexof('w') == 3 // not found - return size of arraysounds like a lot of your code is in fact broken...
I've coded binary searches and sorts tons of times in C++, and yet none was succeptible to this bug. Why? Because, whenever you're talking indices, you should ALWAYS use unsigned int. Since an array can't have negative indices, if you use unsigned ints the problem is solved by design. And, if the element is not found, you throw an exception.
Instead, in C you don't have exceptions, and you have to figure out creative ways for returning errors. errno-like statics work badly with concurrency. And doing something like int search(..., int* err), and setting err inside of your functions, feels cumbersome.
So what does everyone do? Return a positive int if the index is found, or -1 otherwise.
In other words, we artificially extend the domain of the solution just to include the error. We force into the signed integer domain something that was always supposed to be unsigned.
This is the most common cause for most of the integer overflows problems out there.