This gives one method: write a wrapper to malloc to store a pointer to
each block allocated together with the size of the block. Then do an
exhaustive search over all pointers to all elements of all blocks
allocated to find which blocks p and q are in (only needs you to compare
each pointer for equality with p or q, which is legal). And you're done.
p or q may be interior pointers to a malloc'd block.
Just comparing them for equality with the base address won't work.
You need to compare base <= p < (base+size), at which point you're
back to undefined behavior if p is not a pointer into the block.
There isn't any way to do it portably unless you control allocation.
If you use your own heap functions and arrange that all allocations
are made from an array under your control, then you can safely compare
any pointers into those blocks.
But it still won't help in the general case. Technically, by the
standard, comparing unrelated pointers in any way (even for equality)
produces undefined behavior. The exception is that any pointer may be
compared against the constant NULL ... but then the value of NULL is
implementation defined and _not_ guaranteed to be zero.
People have been writing technically non-portable pointer code since
the beginning. Most have just been lucky that the platforms they
targeted had memory layouts which coincidentally corresponded to the
definition of a C array and pointers were simple addresses. As Walter
Roberson mentioned earlier, there are systems in which the notion of a
pointer is more complicated. There are even some systems in which
memory is not organized as an array.
George