重新分配超出范围的操作数据

时间:2019-03-28 13:41:12

标签: c pointers data-structures realloc

我的C代码遇到异常的行为。我正在实现一个最小和最大堆,如果已达到堆容量,则应动态更改大小。问题是,当我调用realloc以增加堆的elements数组时,它以以下方式起作用(假定两个堆都处于最大容量):

  1. 如果仅在其中一个堆中添加一个新元素,则重新分配可以正常工作。

  2. 如果我在两个堆中都添加了一个新元素(一个接一个),则第二个将被完美地重新分配,但是第一个的数据会由于一些垃圾值和一些零而损坏。

请参阅下面的相关功能。 (问题发生在主函数的第8行和第9行)。

我不明白为什么在不同堆上调用insert函数会改变前一个函数的值。

我不知道realloc功能是否混乱或我的打印功能。谢谢您的帮助。

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define leftChild(x) (x << 1)
#define rightChild(x) ((x << 1) + 1)
#define parent(x) (x >> 1)


typedef int T;

typedef struct {
    int size;
    int capacity;
    T *elements;
}   Heap;

void swap(Heap *heap, int a, int b) {
    T temp = heap->elements[a];
    heap->elements[a] = heap->elements[b];
    heap->elements[b] = temp;
}

Heap *newHeap(int capacity) {
    Heap *heap = malloc(sizeof(Heap));
    heap->capacity = capacity;
    heap->size = 0;
    heap->elements = malloc(sizeof(T) * (capacity + 1));
    return heap;
}

void increaseKey(Heap *heap, int i, T key) {
    heap->elements[i] = key;
    while (i > 1 && heap->elements[parent(i)] < heap->elements[i]) {
        swap(heap, parent(i), i);
        i = parent(i);
    }
}

void decreaseKey(Heap *heap, int i, T key) {
    heap->elements[i] = key;
    while (i > 1 && heap->elements[parent(i)] > heap->elements[i]) {
        swap(heap, parent(i), i);
        i = parent(i);
    }
}

void insert(Heap *heap, T key, bool isMinHeap) {
    if (heap->size >= heap->capacity) {
        heap->elements = realloc(heap->elements, heap->capacity * 2);
        heap->capacity = heap->capacity * 2;
    }
    heap->size++;
    heap->elements[heap->size] = 0;
    if (isMinHeap) decreaseKey(heap, heap->size, key);
    else increaseKey(heap, heap->size, key);
}

void printHeap(Heap *heap) {
    int i;
    printf("[");
    for (i = 1; i < heap->size; i++) {
        printf("%d,", heap->elements[i]);
    }
    if (heap->size != 0) {
        printf("%d", heap->elements[heap->size]);
    }
    printf("]\n");
}

int main(void) {
    Heap *minHeap = newHeap(5);
    Heap *maxHeap = newHeap(5);
    for (int i = 0; i < 5; i++) {
        insert(minHeap, i, true);
        insert(maxHeap, i, false);
    }
    printf("now start\n");
    insert(minHeap, 10, true);
    insert(maxHeap, 10, false);
    printHeap(minHeap);
    printHeap(maxHeap);
}

1 个答案:

答案 0 :(得分:2)

您的程序(否则很整洁)中有两个主要错误:

首先,必须为mallocrealloc提供一个字节大小,这意味着除非分配sizeof(T)的数组,否则某个地方应该有一个char。您可以在分配初始数组时执行此操作,但是在重新分配时忘记了它。

第二,您使用基于一个的索引来访问该数组。在C语言中,数组是从零开始的。这也适用于在堆上分配的数据。第一个索引是0,最后一个有效索引是heap->size - 1

这意味着在添加元素时,您将当前大小用作插入索引,然后增加大小。 (当然,您必须首先检查tere是否为空格,但是您必须这样做。)所以:

// ... allocate if necessary ...

heap->elements[heap->size] = 0;
if (isMinHeap) decreaseKey(heap, heap->size, key);
else increaseKey(heap, heap->size, key);

heap->size++;

这是一种常见的模式,在向数组array[size++] = stuff;添加内容时经常会看到。

最后,您可能必须更新确定父级和子级的功能:

parent(n) == (n - 1) / 2;
left(n) == 2*n + 1;
right(n) == 2*n + 2;

使用后,请不要忘记free