Search code examples
cdynamicmemory-leaksvalgrinddynamic-memory-allocation

Dynamic array push() in C causes Valgrind error


Im trying to create a function in C with three input parameters. Dynamic array if integers, its length and integer number. The function will increase the size of dynamic array by one element and put integer number (parameter) as a new element at its end. There is a really simple code, which works, but generates a memory leak error in Valgrind.

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

void pushINT(int*arr,int*size,int data) {
    int*tmp=realloc(arr,(*size+1)*sizeof(int));
    if(tmp==NULL)exit(100);
    else {
        arr[*size]=data;
        (*size)=*size+1;
    }
}

int main() {
    int* array=malloc(0);
    int arraySIZ=0;

    for(int i=0;i<10;i++) pushINT(array,&arraySIZ,i);
    for(int i=0;i<arraySIZ;i++) printf("%d",array[i]);
    printf("\n");

    free(array);
    return 0;
}

Valgrind output:

==19581== Memcheck, a memory error detector
==19581== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==19581== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==19581== Command: /home/filip/Documents/b3b36PRG/HW05/main.c
==19581== 
/home/filip/Documents/b3b36PRG/HW05/main.c: line 4: syntax error near unexpected token `('
/home/filip/Documents/b3b36PRG/HW05/main.c: line 4: `void pushINT(int*arr,int*size,int data) {'
==19581== 
==19581== HEAP SUMMARY:
==19581==     in use at exit: 83,410 bytes in 2,151 blocks
==19581==   total heap usage: 3,812 allocs, 1,661 frees, 145,949 bytes allocated
==19581== 
==19581== 109 (32 direct, 77 indirect) bytes in 1 blocks are definitely lost in loss record 619 of 690
==19581==    at 0x483880B: malloc (vg_replace_malloc.c:309)
==19581==    by 0x192341: xmalloc (in /usr/bin/bash)
==19581==    by 0x146EEE: make_bare_simple_command (in /usr/bin/bash)
==19581==    by 0x146FC5: make_simple_command (in /usr/bin/bash)
==19581==    by 0x141C5B: yyparse (in /usr/bin/bash)
==19581==    by 0x1380C9: parse_command (in /usr/bin/bash)
==19581==    by 0x1381D7: read_command (in /usr/bin/bash)
==19581==    by 0x13845F: reader_loop (in /usr/bin/bash)
==19581==    by 0x136B68: main (in /usr/bin/bash)
==19581== 
==19581== LEAK SUMMARY:
==19581==    definitely lost: 32 bytes in 1 blocks
==19581==    indirectly lost: 77 bytes in 5 blocks
==19581==      possibly lost: 0 bytes in 0 blocks
==19581==    still reachable: 83,301 bytes in 2,145 blocks
==19581==         suppressed: 0 bytes in 0 blocks
==19581== Reachable blocks (those to which a pointer was found) are not shown.
==19581== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==19581== 
==19581== For counts of detected and suppressed errors, rerun with: -v
==19581== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

What causes this problem? I suspect realloc().


Solution

  • The function should be:

    void pushINT(int **arr,int *size,int data) {
        int *tmp=realloc(*arr,(*size+1)*sizeof(int));
        if (tmp==NULL) exit(100);
        *arr= tmp;
        tmp[*size]=data;
        (*size)=*size+1;
    }
    

    Note it now receives a double pointer and remember that realloc can change the memory location. Therefore it is necessary to update the caller's pointer, the reason why it needs a double pointer.


    Or as Jonathan Leffler suggests:

    int *pushINT(int *arr,int *size,int data) {
        int *tmp=realloc(arr,(*size+1)*sizeof(int));
        if (tmp==NULL) exit(100);
        tmp[*size]=data;
        (*size)=*size+1;
        return tmp;
    }