为什么我的代码只能处理这两个空的 print 语句?[关闭]

Why does my code only work with these two empty print statements? [closed]

提问人:gameboy614 提问时间:11/10/2023 更新时间:11/10/2023 访问量:50

问:


编辑问题以包括所需的行为、特定问题或错误以及重现问题所需的最短代码。这将帮助其他人回答这个问题。

11天前关闭。

void siftdown(struct heap *H, int i) {

      int pIndex, lcIndex;
      int siftKey = H->nodes[i];
      int spotFound = 0;
      pIndex = i;

       printf(" ");
      //  printf("first:%d ", H->size);

      while (2 * pIndex + 1 <= H->size - 1 && spotFound == 0) {
        if (2 * pIndex < H->size - 1 &&
            (H->nodes[2 * pIndex + 1] < H->nodes[2 * pIndex + 2])) {
          lcIndex = 2 * pIndex + 2;
          // printf("second:%d ", H->size);
        } else {
          lcIndex = 2 * pIndex + 1;
          // printf("third:%d ", H->size);
        }
        if (siftKey < H->nodes[lcIndex]) {
          H->nodes[pIndex] = H->nodes[lcIndex];
          pIndex = lcIndex;
          // printf("fourth:%d ", H->size);
        } else {
          spotFound = 1;
          // printf("fifth:%d ", H->size);
        }
      }
      H->nodes[pIndex] = siftKey;
    }
    void makeHeap(int n, struct heap *H) {
      H->size = n;
      printf(" ");
      // printf("sixth:%d ", H->size);
      for (int i = floor(n / 2); i >= 0; i--) {
        //printf("\n%d %d", i, H->nodes[i]);
        siftdown(H, i);
      }
    }`

我正在做一个堆的数组实现,并且在 makeHeap 到 siftDown 传递之间,堆大小变为 0,除非存在这两个空的 print 语句。

我假设堆大小>调用是从寄存器读取而不是从内存中获取,但我真的不知道如何解决它。

C 内存 CPU 寄存器

评论

3赞 John Bollinger 11/10/2023
您描述了由边界溢出导致的未定义行为的典型症状。
2赞 Bob__ 11/10/2023
您能否尝试发布一个最小的可重现示例并查看代码格式?
2赞 Scott Hunter 11/10/2023
“从寄存器中读取而不是从内存中获取”:你为什么要这样假设?为什么这很重要?
0赞 John Bollinger 11/10/2023
旁注:ur 是一个整数(截断)除法。结果已经是一个整数,因此传递它没有任何用处。n / 2floor()
0赞 trincot 11/10/2023
你是如何定义的?您是否为 ?使用哪种代码初始化值并调用函数?struct heapH->nodes

答:

1赞 trincot 11/10/2023 #1

在代码的这一部分中,您可以不受检查地访问:H->nodes[2 * pIndex + 2]

  while (2 * pIndex + 1 <= H->size - 1 && spotFound == 0) {
    if (2 * pIndex < H->size - 1 &&
        (H->nodes[2 * pIndex + 1] < H->nodes[2 * pIndex + 2])) {

条件不对。这已经由条件检查过,因此在执行时,这将始终计算为 true。您需要检查节点是否有正确的子节点,条件如下: 。2 * pIndex < H->size - 1while2 * pIndex + 2 < H->size

由于未选中此项,因此可能会遇到超出范围的情况,最终导致超出范围,从而导致使用 写入该位置。这会导致未定义的行为。例如,如果该内存位置恰好被 使用,则此分配会更改大小。lcIndexpIndexH->nodes[pIndex] = siftKey;size

我还将协调所有这些边界检查,使用 and not 以及其他变体。< H->size<= H->size - 1

注意一个问题,但你不需要,因为除法是整数除法。您也可以减少一次迭代,从 开始。makeHeapfloorn/2-1

所以:

void siftdown(struct heap *H, int i) {
  int parentIndex = i;
  int childIndex = i * 2 + 1;
  int siftKey = H->nodes[i];

  while (childIndex < H->size) {
    if (childIndex + 1 < H->size && H->nodes[childIndex] < H->nodes[childIndex + 1]) {
      childIndex++;
    }
    if (siftKey >= H->nodes[childIndex]) {
      break;
    }
    H->nodes[parentIndex] = H->nodes[childIndex];
    parentIndex = childIndex;
    childIndex = 2 * parentIndex + 1;
  }
  H->nodes[parentIndex] = siftKey;
}

void makeHeap(int n, struct heap *H) {
  H->size = n;
  for (int i = n / 2 - 1; i >= 0; i--) {
    siftdown(H, i);
  }
}

评论

0赞 trincot 11/11/2023
你检查过这个解决方案吗?它解决了你的问题吗?