I know there are tons of other realloc questions and answers and I have read almost all of them, but I still couldn't manage to fix my problem.
I decided to stop trying when I accidentaly discovered a very strange behaviour of my code.
I introduced a line to try something, but although I don't use the value of newElems
in main, the line changes the behaviour.
When the line is commented, the code fails at first realloc
. Including the line, the first realloc works. (it still crashes on the second one).
Any ideas on what might be happening?
int main(int argc, char** argv) {
Pqueue q = pqueue_new(3);
Node a = {.name = "a"}, b = {.name = "b"},
c = {.name = "c"}, d = {.name = "d"};
push(& q, & a, 3);
// the next one is the strange line: as you can see, it doesn't modify q
// but commenting it out produces different behaviour
Pqueue_elem* newElems = realloc(q.elems, 4 * q.capacity * sizeof *newElems);
push(& q, & b, 5);
push(& q, & c, 4);
char s[5];
Node* n;
for (int i = 1; i <= 65; ++i) {
sprintf(s, "%d", i);
n = malloc(sizeof *n);
n->name = strdup(s);
push(& q, n, i);
}
Node* current = NULL;
while ((current = pop(& q))) {
printf("%s ", current->name);
}
return 0;
}
and the push function:
void push(Pqueue* q, Node* item, int priority) {
if (q->size >= q->capacity) {
if (DEBUG)
fprintf(stderr, "Reallocating bigger queue from capacity %d\n",
q->capacity);
q->capacity *= 2;
Pqueue_elem* newElems = realloc(q->elems,
q->capacity * sizeof *newElems);
check(newElems, "a bigger elems array");
q->elems = newElems;
}
// append at the end, then find its correct place and move it there
int idx = ++q->size, p;
while ((p = PARENT(idx)) && priority > q->elems[p].priority) {
q->elems[idx] = q->elems[p];
idx = p;
}
// after exiting the while, idx is at the right place for the element
q->elems[idx].data = item;
q->elems[idx].priority = priority;
}
The pqueue_new function:
Pqueue pqueue_new(unsigned int size) {
if (size < 4)
size = 4;
Pqueue* q = malloc(sizeof *q);
check(q, "a new queue.");
q->capacity = size;
q->elems = malloc(q->capacity * sizeof *(q->elems));
check(q->elems, "queue's elements");
return *q;
}
Thank you all for the suggestions! I wouldn't have solved it without them,
The strange behaviour was caused by an off by one error. I was reallocating the queue only when q->size >= q->capacity
, but since q was indexed from 0, it meant that before realloc
I was writing in a forbidden location (q->elems[q->size]
), which messed everything up.