【问题标题】:Binary search accessing out of range index二分查找访问超出范围的索引
【发布时间】:2017-01-10 05:37:50
【问题描述】:

这是代码:

char binarySearch(unsigned int target, int* primes, unsigned int size){
    int* ptrToArray = primes;
    unsigned int first = 0;
    unsigned int last = size;

    while (first <= last){
        unsigned int middle = first + (last - first) / 2;
        printf("first: %d, last: %d, middle: %d\n", first, last , middle);

        if (ptrToArray[middle] == target){
            return 1;
        }

        if (ptrToArray[middle] < target){
            first = middle + 1;
        }else{
            last = middle - 1;
        }
    }
    return 0;
}

这是输出:

我一直盯着这种平静的代码看不止一个,但仍然无法弄清楚缺陷在哪里。

【问题讨论】:

  • @Thomas 是的,没错。
  • 如果size 不是有效值,您必须处理这种情况。
  • 另外,简单的数学简化了first + (last - first) / 2,所以更清楚的是它是中间的。
  • 也就是说如果size &lt;= 0,你应该返回一些错误让用户知道数组不正确。
  • 尝试 unsigned int last = size-1;而不是 unsigned int last = size;

标签: c arrays algorithm search


【解决方案1】:

如果middle0,则在调试输出接近尾声时,声明

last = middle - 1

导致整数溢出;条件需要修改一下。

【讨论】:

  • 可能是:last = (middle &gt; 0)? middle - 1 : 0;
  • last = middle;,就是这样。你总会得到一个新的middle
  • @Ziezi 没有负数,所以使用unsigned int 是安全的,不会引起别人说什么,除了middle - 1,所以这是正确答案。请注意,middle = (first + last) / 2 始终是正数,您只是以带有- 符号的方式编写它,对于没有经验的人来说可能看起来很危险。
【解决方案2】:

问题在于您将索引变量(firstlastmiddle)定义为unsigned int,而在您的逻辑中,last 实际上可以变为负数。但是,在这种情况下,由于它们被定义为 unsigned 并且由于负数的 2 的补码表示的工作方式,while 循环中的条件仍然为真。

请看以下示例代码进行说明:

#include <stdio.h>

int main() {
  /* defining the variables as unsigned */
  unsigned int first_u = 0;
  unsigned int last_u = -1;

  if (first_u <= last_u)
    printf("less than\n");
  else
    printf("greater or equal\n");

  /* defining the variables as signed */
  int first_s = 0;
  int last_s = -1;

  if (first_s <= last_s)
    printf("less than\n");
  else
    printf("greater or equal\n");

  return 0;
}

除此之外,您应该在while 条件中使用&lt;,或者将last 的初始值定义为size-1。否则,如果您要搜索的元素大于数组中的最后一个元素,则会超出范围。

【讨论】:

    【解决方案3】:

    当您查找不在数组中的元素时,您可能会超出范围,并且大于数组,因为当lastfirstwhile (first &lt;= last) 中彼此相等时允许保持迭代/p>

    想想当你发送一个空数组时会发生什么:size == 0:

    first = 0, last = 0,因此:(first &lt;= last) == true
    然后,middle = 0 + (0 - 0)/2 = 0,接下来您访问的是超出范围的ptrToArray[0]

    【讨论】:

      【解决方案4】:

      首先中间的负值是由于溢出(无符号整数)。

      另外我认为你应该有: unsigned int last = size-1 因为如果 first 等于 last=size 你将使用 ptrToArray[middle] 和 middle=size 所以它将超出数组范围。这也将解决上面提到的 size =0 的情况。

      最后,为了让您的代码更易于阅读,您可以编写: middle =(first+last)/2 是 [first,last] 空格的中间,equals to first+(last-first)/2

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-11
        相关资源
        最近更新 更多