Im writing a simple array. And how i think, do it correct in terms of leaks. But valgrind doesnt think so. Why? That phantom leak just because i do more malloc then free?
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CAPACITY_INCREACE(arr) ((int)(arr->capacity * 1.5f))
#define CAPACITY_DEFAULT 5
typedef struct array
{
int capacity;
int size;
int* arr;
} array;
array* create_array()
{
array* arr = (array*)malloc(sizeof(array));
arr->capacity = CAPACITY_DEFAULT;
arr->size = 0;
arr->arr = (int*)malloc(arr->capacity * sizeof(int));
return arr;
}
void print_array(array *arr)
{
printf("array, size - %d, capacity - %d\n", arr->size, arr->capacity);
for(int i = 0; i < arr->size; ++i)
printf("%d ", arr->arr[i]);
printf("\n");
}
void realloc_array(array* arr, int size)
{
int* new_arr = (int*)malloc(size * sizeof(int));
memcpy((void*)new_arr, arr->arr, arr->size * sizeof(int));
arr->arr = new_arr;
}
void add(array* arr, int element)
{
if((arr->size + 1) <= arr->capacity)
{
arr->arr[arr->size++] = element;
return;
}
arr->capacity = CAPACITY_INCREACE(arr);
realloc_array(arr, arr->capacity);
arr->arr[arr->size++] = element;
}
void delete_array(array *arr)
{
free(arr->arr);
free(arr);
}
int main(int argc, int** argv)
{
array* arr = create_array();
for(int i = 0; i < 8; i++)
add(arr, i);
print_array(arr);
delete_array(arr);
return 0;
}
Valgrind run and program compile
gcc -g array.c && ./a.out
valgrind --leak-check=full -s ./a.out
Info from valgrind, he show me where, but unfortunately im not understand what im doing wrong:
HEAP SUMMARY:
in use at exit: 48 bytes in 2 blocks
total heap usage: 5 allocs, 3 frees, 1,128 bytes allocated
20 bytes in 1 blocks are definitely lost in loss record 1 of 2
by 0x10920B: create_array (array.c:21)
by 0x109443: main (array.c:71)
28 bytes in 1 blocks are definitely lost in loss record 2 of 2
by 0x10930C: realloc_array (array.c:43)
by 0x1093CD: add (array.c:57)
by 0x10946D: main (array.c:74)
LEAK SUMMARY:
definitely lost: 48 bytes in 2 blocks
indirectly lost: 0 bytes in 0 blocks
possibly lost: 0 bytes in 0 blocks
still reachable: 0 bytes in 0 blocks
suppressed: 0 bytes in 0 blocks
The function
void realloc_array(array* arr, int size)
{
int* new_arr = (int*)malloc(size * sizeof(int));
memcpy((void*)new_arr, arr->arr, arr->size * sizeof(int));
arr->arr = new_arr;
}
is throwing away the original buffer arr->arr
without freeing.
Add call to free()
to avoid memory leak.
void realloc_array(array* arr, int size)
{
int* new_arr = (int*)malloc(size * sizeof(int));
memcpy((void*)new_arr, arr->arr, arr->size * sizeof(int));
free(arr->arr); /* add this */
arr->arr = new_arr;
}
Or use standard realloc()
.
void realloc_array(array* arr, int size)
{
int* new_arr = realloc(arr->arr, size * sizeof(int));
if (new_arr == NULL) exit(1);
arr->arr = new_arr;
}
Also note that casting results of malloc()
family is considered as a bad practice.