I'm a bit new to C-programming and I can't seem to understand where should I free the int* array I initialized. I tried to put free(array) after I've got what I need but Valgrind still reports a memory leak and an invalid free at the location I proposed. Where should I put the free(array) call in this code?
Note: the actual code implementation is removed to make the code simpler while retaining the bug.
// C-language code (C99)
#include <stdio.h>
#include <stdlib.h>
int fib(int index, int *array, int initBlocks);
int processFib(int index);
int doubleStorage(int **array, int initialBlocks);
int main() {
int ans = processFib(10);
printf("ans = %d", ans);
return 0;
}
// initialises an array and calls the fib(...) function
int processFib(int index) {
int defaultInitBlocks = 10;
int *array = calloc(defaultInitBlocks, sizeof(int));
array[1] = 1;
array[2] = 1;
int ans = fib(index, array, defaultInitBlocks);
free(array); /* Valgrind says InvalidFree here ----------------------*/
return ans;
}
// doubles storage of array using realloc
int doubleStorage(int **array, int initialBlocks) {
int factor = 2;
int *temp = realloc(*array, factor * initialBlocks * sizeof(int));
/* Valgrind says the realloc here is a DefinitelyLost memory leak --------*/
if (!temp) {
free(*array);
return -1;
} else {
*array = temp;
for (int i = initialBlocks; i < factor * initialBlocks; i++) {
(*array)[i] = 0;
}
return factor * initialBlocks;
}
}
// doubles storage if 'index' is greater than array storage. Else, returns 1
int fib(int index, int *array, int initBlocks) {
if (index >= initBlocks) {
int newBlocks = doubleStorage(&array, initBlocks);
return fib(index, array, newBlocks);
}
return 1;
}
EDIT: SOLUTION MOVED TO ANSWERS
SOLUTION
A double pointer is now used in the fib() function which cleared the Valgrind warning (code below). Heads up to #WhozCraig for his comment.
int fib(int index, int **array, int initBlocks) {
if (index >= initBlocks) {
int newBlocks = doubleStorage(array, initBlocks);
return fib(index, array, newBlocks);
}
if (array[index] > 0) {
return (*array)[index];
} else {
(*array)[index] = fib(index - 1, array, initBlocks)
+ fib(index - 2, array, initBlocks);
return (*array)[index];
}
}
Related
#include <stdio.h>
#include <stdlib.h>
int find_lenght(int *arrr){
int i = 0;
while(arrr[i] != '\0'){
i++;
}
return i;
}
void init_array(int *arrr){
arrr=(int*)malloc(1*sizeof(int));
printf("New element:");
int lenght = find_lenght(arrr);
scanf("%d", &arrr[lenght]);
printf("Lenght = %d\n",lenght);
printf("Array elements are:\n");
for(int i = 0; i <= lenght; i++) {
printf("%d,", arrr[i]);
}
}
void print_array(int *arrr){
printf("Array elements are:\n");
int lenght = find_lenght(arrr);
for(int i = 0; i == lenght; i++) {
printf("%d,", arrr[i]);
}
}
int main() {
int *arr = NULL;
init_array(arr);
print_array(arr);
}
I don't know what am i missing here.
My point is to fill in and then print dynamic array
Also my taught is it's not filling the way it should, so it hasn't anything to print.
Your arr pointer in main is never assigned because your init_array assign the address of the allocated memory (the return value of malloc) to the input parameter arrr, which is, a local variable.
You have mainly two solutions to properly achieve what you want to do. The first one (the better one in my point of view), by making your init_array returning the allocated memory address to be assigned:
int* init_array()
{
int* retval = (int*)malloc(1*sizeof(int));
// ...
return retval;
}
int main()
{
int *arr = init_array(); //< assign arr with returned value
}
Another way is to make your init_array function taking a pointer to a pointer, so the function can assign this pointer:
void init_array(int** arrr)
{
(*arrr) = (int*)malloc(1*sizeof(int));
// ...
}
int main()
{
int* arr = NULL;
init_array(&arr); //< pass reference to arr
}
You need to pass the pointer to pointer to int to change passed pointer. Your for loop is invalid in print function. You need also to set the sentinel value yourself.
size_t find_length(const int *arrr)
{
size_t i = 0;
if(arrr)
while(arrr[i]) i++;
return i;
}
void add_element(int **arrr, int element)
{
size_t length = find_length(*arrr);
int *tmp = realloc(*arrr, (length + 2) * sizeof(**arrr));
if(tmp)
{
*arrr = tmp;
(*arrr)[length] = element;
(*arrr)[length + 1] = 0;
}
}
void print_array(const int *arrr)
{
printf("Array elements are:\n");
size_t lenght = find_length(arrr);
for(size_t i = 0; i < lenght; i++)
{
printf("arrr[%zu] = %d\n", i, arrr[i]);
}
}
int main(void) {
int *arr = NULL;
add_element(&arr, 5);
add_element(&arr, 15);
add_element(&arr, 25);
add_element(&arr, 35);
print_array(arr);
}
https://godbolt.org/z/drKej3KT5
the array on your main function is still NULL. the better way to do is just call the print_array() function after you initialize it. you just simply put print_array(arrr) inside init_array() and after the for loop statement.
The line
int lenght = find_lenght(arrr);
may invoke undefined behavior, because find_length requires its argument to be a pointer to the first element of a null-terminated int array. However, the content of the memory pointed to by arrr is indeterminate, because it has not been initialized. Therefore, it is not guaranteed to be null-terminated.
So, I have a dynamic array which leaks memory and I can almost always find out that all memory lost is lost in ONE block, and sometimes it didn't leak anything. However, I changed something, and now it always leaks, but it's a computable sum (I think it's the size of the array we last get before quitting the program). Can you please help me with this?
Here's the code if you want to look into it:
#include "DynamicVector.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
DynamicVector createDynamicVector() {
DynamicVector dynamicVector;
dynamicVector.number_of_elements = 0;
dynamicVector.capacity = 2;
dynamicVector.elements = (int *)malloc(dynamicVector.capacity * sizeof(int));
return dynamicVector;
}
int isEmpty(DynamicVector *pointer) {
if (pointer->number_of_elements == 0)
return 1;
return 0;
}
int search_element(DynamicVector *pointer, int element) {
int index;
for (index = 0; index < pointer->number_of_elements; index++) {
if (pointer->elements[index] == element) {
return index;
}
}
return -1;
}
void resize_smaller(DynamicVector *pointer) {
int *new_elements;
new_elements = (int *)malloc((pointer->capacity * 3 / 4) * sizeof(int));
memcpy(new_elements, pointer->elements, pointer->number_of_elements * sizeof(int));
destroyDynamicVector(pointer);
pointer->elements = new_elements;
pointer->capacity = pointer->capacity * 3 / 4;
}
void resize_bigger(DynamicVector *pointer) {
int *new_elements;
new_elements = (int *)malloc(pointer->capacity * 2 * sizeof(int));
memcpy(new_elements, pointer->elements, pointer->number_of_elements * sizeof(int));
destroyDynamicVector(pointer);
pointer->elements = new_elements;
pointer->capacity = pointer->capacity * 2;
}
void add_element(DynamicVector *pointer, int element) {
if (pointer->capacity == pointer->number_of_elements) {
resize_bigger(pointer);
}
*(pointer->elements + pointer->number_of_elements) = element;
pointer->number_of_elements++;
}
int remove_element(DynamicVector *pointer, int element) {
int index_found = 0;
index_found = search_element(pointer, element);
if (index_found == -1) {
return 1;
}
*(pointer->elements + index_found) = *(pointer->elements + pointer->number_of_elements - 1);
pointer->number_of_elements--;
if (pointer->number_of_elements < pointer->capacity / 2) {
resize_smaller(pointer);
}
return 0;
}
void destroyDynamicVector(DynamicVector *pointer) {
free(pointer->elements);
}
The code seems fine, you should post the structure definition and a main() function that exhibits the leak. It is possible that this leak be unrelated to your code: also explain what tool you are using to detect memory leaks.
There is a small issue for huge vector sizes where pointer->capacity * 3 / 4 might cause an integer overflow. This overflow could cause the malloc() to fail and return NULL, prompting undefined behavior when copying the array contents.
You could also use realloc() instead of malloc() for resizing, saving some copying if the block can be resized in place:
int resize_bigger(DynamicVector *pointer) {
size_t new_capacity = pointer->capacity * 2;
int *new_elements = realloc(pointer->elements, new_capacity * sizeof(int));
if (new_elements != NULL) {
pointer->elements = new_elements;
pointer->capacity = new_capacity;
return 0;
} else {
return -1;
}
}
void resize_smaller(DynamicVector *pointer) {
size_t new_capacity = pointer->capacity - pointer->capacity / 4;
int *new_elements = realloc(pointer->elements, new_capacity * sizeof(int));
if (new_elements != NULL) {
pointer->elements = new_elements;
pointer->capacity = new_capacity;
}
}
// return the element number or -1 in case of failure
int add_element(DynamicVector *pointer, int element) {
if (pointer->capacity == pointer->number_of_elements) {
if (resize_bigger(pointer))
return -1;
}
pointer->elements[pointer->number_of_elements] = element;
return pointer->number_of_elements++;
}
When you add element , you multiply size by 2 but when you remove element ou keep 3/4. That means that after adding one element and removing element the size will be 2*3/4=1.25 the original size.
I'm trying to add new element to dynamic array in C (I know that I must free all memory. I will do it later), but I get this error every time:
But, what is strange, if I compile from terminal, like that, code works properly.
So, where is the error and how i can beat it?
Thank you!
All my code:
main.c
#include <stdio.h>
#include <stdlib.h>
typedef struct vector
{
int size;
int *array;
int alreadyIn;
}vector;
vector *vectorInit(int size)
{
vector *newVec = (vector *)malloc(sizeof(vector));
if(!newVec){printf("No memory!\n"); return NULL;}
newVec->size = size;
newVec->array = (int *)malloc(size * sizeof(int));
return newVec;
}
void allocNewMemory(vector *vect, int howMuch)
{
vect->array = (int *)realloc(vect->array ,(vect->size + howMuch) * sizeof(int));
vect->size += howMuch;
}
void pushBack(vector *vect, int number)
{
int howMuch = 5;
if(vect && vect->alreadyIn < vect->size)
{
vect->array[vect->alreadyIn] = number;
vect->alreadyIn++;
}
else
{
printf("Alloc new memory for %d elements...\n", howMuch);
allocNewMemory(vect, howMuch);
pushBack(vect, number);
}
}
void printVector(vector *vect)
{
for (int i = 0; i < vect->alreadyIn; i++)
{
printf("%d ", vect->array[i]);
}
printf("\n");
}
int main()
{
int startSize = 4;
vector * vec = vectorInit(startSize);
for (int i = 0; i < 6; i++)
{
pushBack(vec, i+1);
}
printVector(vec);
return 0;
}
You never initialize the alreadyIn member in the structure. That means its value will be indeterminate (and seemingly garbage or random).
You need to explicitly initialize it to zero:
vector *vectorInit(int size)
{
vector *newVec = malloc(sizeof(vector));
if(!newVec)
{
printf("No memory!\n");
return NULL;
}
newVec->size = size;
newVec->array = malloc(size * sizeof(int));
newVec->alreadyIn = 0; // Remember to set this to zero
return newVec;
}
This problem should have been easy to detect in the debugger.
Also note that I removed the casts from malloc. One should not cast the result of malloc, or really any function returning void *.
Im writing a program with a function add(a , i, n) which will add 'i' as an element to 'a', but if the array 'a' runs out of space, then I need to realloc more memory to the array. Im stuck here:
#include <stdlib.h>
#include <stdio.h>
int add(int* a, int i, int n);
int main(){
int n = 20;
int *a = (int*) malloc(n*sizeof(int));
int i;
for (i = 0; i < 100000; i++){
n = add(a, i, n);
printf("a[%d]=%d\n",i,(int)a[i]);
}
return 0;
}
int add(int *a, int i, int n){
if (i >= n){
n++;
int* b = (int*) realloc(a, n*sizeof(int));
a[i]=i;
return n;
}else{
}
}
Im not very experienced so please be gentle...
realloc tries to reallocate the given memory, but sometimes, it can't and gives you a new memory pointer.
It must be used like:
int *b;
b = realloc(a, <newsize>);
if (b) {
/* realloc succeded, `a` must no longer be used */
a = b;
/* now a can be used */
printf("ok\n");
} else {
/* realloc failed, `a` is still available, but it's size did not changed */
perror("realloc");
}
Now, you still have some trouble in your code:
The idea of function add() is to reallocate a when needed, but a is given by copy, so its value won't be changed in main.
#include <stdlib.h>
#include <stdio.h>
int add(int** a, int i, int n);
int main(){
int n = 20;
int *a = malloc(n*sizeof(int));
int i;
for (i = 0; i < 100000; i++) {
/* note how `a` is passed to `add` */
n = add(&a, i, n);
printf("a[%d]=%d\n",i,a[i]);
}
/* and finally free `a`*/
free(a);
return 0;
}
/* changed `a` type to make its new value visible in `main` */
int add(int **a, int i, int n){
if (i >= n){
/* want to write a[i], so size must be at least i+1*/
n = i+1;
/* realloc memory */
int *b = realloc(*a, n*sizeof(int));
/* check that `realloc` succeded */
if (!b) {
/* it failed!*/
perror("realloc");
exit(1);
}
/* store new memory address */
*a = b;
}
/* update memory */
(*a)[i]=i;
/* return new size */
return n;
}
Note: I removed malloc/realloc cast, see: Do I cast the result of malloc?
To have an automatically growing array in C you would normally need a helper function ensure_capacity to take care of the array reallocation.
The helper function would preferrably reallocate using 2x grow policy, so you have an amortized constant time of the append operation.
The code would look somewhatlike the below.
Note that the code is using the first 2 elements of the array to keep its capacity/size. You can use a struct of pointer + size instead, but you need to keep the two close two each other as otherwise the code won't be easy to read.
int* ensure_capacity(int* vec, int new_cap) {
if (vec == 0) {
vec = (int*) malloc(18 * sizeof(int));
vec [0] = 16;
vec [1] = 0;
} else {
int cap = vec[0];
if (cap < new_cap) {
do {
cap *= 2;
} while (cap < new_sz);
int* new_vec = (int*) realloc(vec, cap * sizeof(int));
if (new_vec != null) {
vec = new_vec;
vec[0] = cap;
} else {
// reallocation failed, handle the error
}
}
}
return vec;
}
And you would use it in your add() function like:
int* push_back(int* vec, int val) {
vec = ensure_capacity(vec, vec[1] + 1);
vec[vec[1]++] = val;
return vec;
}
my Excercice is to initalise space from the heap in function1(); and to create an array there. In the main I have to print the array. What have I done wrong?
CODE
#include <stdio.h>
#include <stdlib.h>
int functionOne(int size);
int main()
{
int size = 0,i;
scanf("%d",&size);
int *arrsize = functionOne(size);
printf("rueckgabe %d",arrsize);
int arr [*arrsize];
arr[0] = 7;
arr[1] = 2;
arr[2] = 3;
arr[3] = 4;
arr[4] = 5;
for(i=0; i<size; i++)
{
printf("[%d]",arr[i]);
}
}
int functionOne(int size)
{
int *arr;
arr = NULL;
arr = malloc(size * sizeof(int));
return arr;
}
The thing is on the line printf("rueckgabe %d",arrsize); you are printing the address returned by other function - that too using wrong format specifier.
Suppose you allocated memory for 4 int using the other function functionOne and the memory of the allocated chunk is being returned - now when you do *arrsize you are basically accessing the 0th positional int value. But as it is uninitialized - the value of it is indeterminate.
Earlier you were declaring VLA with uninitialized value. This is undefined behavior. Also there is no meaning printing the contents of the variable length array unless you initialize them (i.e.,printf("[%d]",arr[i]);).
Return value of the function functionOne is int but you are returning int*.
There are many other things you can follow in the code, like correcting the indentation - checking the return value of malloc and changing the signature of main from int main() to int main(void).
I have added some demo code showing whatever I have mentioned above:
Edit:
#include <stdio.h>
#include <stdlib.h>
int* functionOne(int size);
int main(void)
{
int size = 0;
if( scanf("%d",&size)!= 1){
fprintf(stderr,"Error in input\n");
exit(EXIT_FAILURE);
}
if( size <= 0){
fprintf(stderr,"Error in input [size]\n");
exit(EXIT_FAILURE);
}
int *arr = functionOne(size);
for(size_t i = 0; i < size; i++){
arr[i]=i;
}
for(size_t i = 0; i<size; i++){
printf("arr[%zu] = %d \n",i,arr[i]);
}
free(arr);
return 0;
}
int* functionOne(int size)
{
int *arr;
arr = malloc(sizeof(int)*size);
if( arr == NULL && size > 0){
perror("malloc");
exit(EXIT_FAILURE);
}
return arr;
}