2

TL;DR: Am I correctly passing my array into grow()?

I am trying to dynamically resize an array when adding elements to it. Currently I am getting an error message:

free(): double free detected in tcache 2

I am very sure that I am somehow passing this argument incorrectly but I'm relatively knew to pointers so I could use a tip. here is my main function, I've stripped out most of it. The problem is most like with the add() and grow() methods.

Edit: I should add that if I bypass add() just try calling grow() from main it works correctly.

main:

int main(int argc, char *argv[]){
    // declaring the dynamic array 
    const int SIZE = 2;
    float * q;
    q = (float*)malloc(sizeof(float) * SIZE); // initial memory allocation 
    int tail = 0;   // tail is the index in which we will add items
    int capacity = SIZE; 

    // add stuff to the array
    add(10.0, q, &tail, &capacity);
    add(20.0, q, &tail, &capacity); // crashes during this call!

    return 0;
}

Here are my add() and grow() methods which are contained in another file. Everything seems to be working great until I try to call grow for the second time.
add:

void add(float element, float* q, int* tail, int* capacity){
    // add the element 
    q[*tail] = element;

    // increment tail
    ++*tail;

    // do we need to resize the array?
    if(*tail >= (*capacity) / 2){
        // capacity is already an int* so we don't need the & symbol
        grow(&q, *capacity);
        // update capacity
        *capacity = (*capacity) * 2;
    }
    return;
}

grow

void grow(float* *q, const int capacity){
    printf("# start of grow... capacity = %d\n", capacity);

    // creating temp array 
    float  * tmp = (float*)malloc(sizeof(float) * (capacity * 2));

    // copying values
    int i;
    for (i = 0; i < capacity; ++i){
        tmp[i] = (*q)[i];
    }

    // de-allocate old q
    free(*q);

    // re-assign 
    *q = tmp;
}
jbakerj
  • 55
  • 1
  • 6

1 Answers1

3
void add(float element, float* q, int* tail, int* capacity){
* * *
        grow(&q, *capacity);

You pass the inner q, used in the add. Not the original one. Like changing any other parameter (for example, element = 1.0) it'll not affect the q in main.

You should pass it like

void add(float element, float* *q, int* tail, int* capacity){
* * *
        grow(q, *capacity);

and call it like

add(10.0, &q, &tail, &capacity);

in order to make the q itself as changeable, as tail and capacity currently are. Also, grow can be easily replaced with realloc().

NickDoom
  • 339
  • 1
  • 9
  • 2
    Beyond this, I'd recommend a redesign to put `q`, `capacity` and `tail` into a struct. `add(20.0, &q, &tail, &capacity);` is too burdensome for the caller. – ggorlen Feb 19 '20 at 23:24
  • I see, I'm updating a local version! That would explain it. Thanks! – jbakerj Feb 19 '20 at 23:28