简体   繁体   English

如何检查指针是否指向数组内的元素?

[英]How to check whether a pointer is pointing to an element inside an array?

The following function intends to check whether the pointer b is pointing to the array a[0],...,a[len-1] ? 以下函数旨在检查指针b是否指向数组a[0],...,a[len-1]

bool between(int *a, int len, int *b)
{
    return (a <= b) && (b < a + len);
}

From reading https://en.cppreference.com/w/c/language/operator_comparison the function invokes undefined behaviour. 通过阅读https://en.cppreference.com/w/c/language/operator_comparison,该函数调用未定义的行为。 If so, what is the right way to do this? 如果是这样,这样做的正确方法是什么? Why does the standard disallow this? 为什么标准不允许这样做?

Comparing two unrelated pointers (ie pointers that don't point to members of the same array object or struct) using the comparison operators < , <= , > , and >= do indeed invoke undefined behavior as described in the linked page as well as section 6.5.8 of the C standard . 使用比较运算符<<=>>=比较两个不相关的指针(即不指向同一数组对象或结构的成员的指针)确实调用链接页面中描述的未定义行为以及C标准第6.5.8节。

As to why this is disallowed, not all implementations have a flat memory model, and unrelated objects need not reside in areas of memory where performing a comparison makes sense. 至于为什么不允许这样做,并非所有实现都具有平坦的存储器模型,并且不相关的对象不需要驻留在执行比较的存储器区域中。

So your function would return true in cases where b points to a member of a , false when it points one past the last member of a , and would invoke undefined behavior otherwise. 所以,你的函数将返回在案件真实b点的成员a ,假当它指向一个过去的最后一个成员a ,和原本调用未定义的行为。

It is however allowed to compare unrelated pointers using == or != . 但是,允许使用==!=来比较不相关的指针。 So you can circumvent the limitation on comparison operators by looping through the array and using equality operators to compare the target pointer with each element: 因此,您可以通过循环遍历数组并使用相等运算符将目标指针与每个元素进行比较来规避比较运算符的限制:

bool between(int *a, int len, int *b)
{
    int i;
    for (i=0; i<len; i++) {
        if (a+i == b) {
            return true;
        }
    }
    return false;
}

While this is not a efficient as a ranged check, it is the only compliant way to do so. 虽然这不是一个有效的远程检查,但它是唯一合规的方法。

Of course, it would be better to construct your program in such a way that such a comparison is not necessary. 当然,最好以这样的方式构建程序,以便不需要这样的比较。 A program that is allowing a pointer to inside an array to fall outside of the array is already invoking undefined behavior, so fixing that would eliminate the need for such a function. 允许指向数组内部的指针落在数组之外的程序已经在调用未定义的行为,因此修复它将不再需要这样的函数。

Note however that it is allowed to increment a pointer to one element past the end of an array and perform comparisons on that pointer (although it cannot be dereferenced). 然而,注意,它允许一个指针递增到一个元件过去的阵列的端部和在该指针执行比较(尽管它不能被解除引用)。

In addition to @dbush good answer, code can do math on the array side a to achieve a potential quicker positive result. 除了@dbush很好的答案,代码可以做阵列侧数学a ,实现了更快的潜在积极的结果。

By attempting a binary search first, if the outcome of between() is true and the mapping of pointers to integers are in a common implementation, the true value will be found in O(log(n)) time. 通过首先尝试二进制搜索,如果between()的结果为true并且指向整数的映射在通用实现中,则true值将在O(log(n))时间内找到。

If b is not found in the array via the binary search, a linear is still needed to cope with unusual mapping of pointers to integers. 如果通过二进制搜索在数组中找不到b ,则仍然需要线性来处理指针到整数的异常映射。

For large arrays, like n=1,000,000 the log2(1,000,000) steps of doing a bsearch is insignificant. 对于大型数组,例如n=1,000,000 ,执行bsearch的log2(1,000,000)步骤是无关紧要的。 For small arrays, best to proceed directly to the loop. 对于小型阵列,最好直接进入循环。

 // When optional, but common, uintptr_t available
int fcmp(const void *key, const void *array_element) {
  if (key == array_element) {
    return 0;
  }
  uintptr_t ai = (uintptr_t) array_element;
  uintptr_t ki = (uintptr_t) key;
  return (ai > ki) - (ai < ki);
}

// Best to use `size_t` for array indexing
bool between(int *a, size_t a_sz, int *b) {
  if (bsearch(b, a, a_sz, sizeof *a, fcmp)) {
    return true;
  }
  for (size_t i = 0; i < a_sz; i++) {
    if (a + i == b) {
      return true;
    }
  }
  return false;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM