So I have a function that returns a pointer to an element in an array A. I have another function that takes that pointer as a parameter. However, I need that function to be able to deal with the possibility that it may be passed a completely arbitrary pointer.
Is there a way to be able to detect if a pointer points somewhere within a structure? In this case, my array A?
I've seen similar questions regarding C++, but not with C.
The only portable way is to use an equality test against all of the possible valid values for the pointer. For example:
int A[10];
bool points_to_A(int *ptr)
{
for (int i = 0; i < 10; ++i)
if ( ptr == &A[i] )
return true;
return false;
}
Note that using a relational operator (e.g. <
), or subtraction, with two pointers is undefined behaviour unless the two pointers actually do point to elements of the same array (or one past the end).
In section §6.5.8 Relational operators, the C11 standard (ISO/IEC 9899:2011) says:
When two pointers are compared, the result depends on the relative locations in the address space of the objects pointed to. If two pointers to object types both point to the same object, or both point one past the last element of the same array object, they compare equal. If the objects pointed to are members of the same aggregate object, pointers to structure members declared later compare greater than pointers to members declared earlier in the structure, and pointers to array elements with larger subscript values compare greater than pointers to elements of the same array with lower subscript values. All pointers to members of the same union object compare equal. If the expression P
points to an element of an array object and the expression Q
points to the last element of the same array object, the pointer expression Q+1
compares greater than
P
. In all other cases, the behavior is undefined.
If you know that the pointer is within range of the array, then comparisons work. If the pointer is outside the range, you can't be sure that the comparisons will work. In practice, it usually does, but the standard explicitly says that the comparison yields undefined behaviour.
Note that for an array SomeType array[20];
, the address &array[20]
is guaranteed to be valid and to compare reliably with any address from &array[0]
through &array[19]
. You need to decide whether you want to count that as being in your array.
Subject to the observation that the standard does not guarantee that it will work, then, you can compare two int
pointers:
int within_int_array(int *array, size_t num_ints, int *ptr)
{
return ptr >= array && ptr < array + num_ints;
}
These days, you should be increasingly cautious about invoking undefined behaviour. Compilers do nasty things to programs that use undefined behaviour, and technically, you have no recourse since the standard says "undefined behaviour".