Regarding free function in c - c

May I know that if I free something in C programming language and I declare it as pointer before, it would just free out the memory but the pointer is still there or the pointer data type will also be destroyed as the code below. Also, may I know that if I want to free up my memory in this situation, why would I use free(list) in the end instead of using free(tmp)? Below is my code:
#include <stdio.h>
#include <stdlib.h>
int main(void){
int *list = malloc(3 *sizeof(int));
if (list==NULL){
return 1;
}
list[0] = 1;
list[1] = 2;
list[2] = 3;
int *tmp = malloc(4 * sizeof(int));
if (tmp==NULL){
free(list);
return 1;
}
for (int i = 0; i < 3; i++){
tmp[i] = list[i];
}
tmp[3] = 4;
free(list);
list = tmp;
for (int i = 0; i < 4; i++){
printf("%i\n", list[i]);
}
free(list);
}

Calling free does not affect the pointer or its contents, just what the pointer pointed to. But the value in that pointer should no longer be considered valid.
The part about your specific use of free was addressed in the comments.

In these declarations
int *list = malloc(3 *sizeof(int));
int *tmp = malloc(4 * sizeof(int));
you declared two pointers list and tmp that has automatic storage duration. The pointers themselves point to dynamically allocated arrays that (the memory occupied by the arrays) should be freed using the function free to avoid memory leaks.
After calling the function free the pointers will have invalid values.
What the program is doing is at first it allocated dynamically an integer array with three elements and the address of the allocated memory is assigned to the pointer list.
int *list = malloc(3 *sizeof(int));
Then the program tries to reallocate the array by means at first of allocating dynamically a new array with four elements
int *tmp = malloc(4 * sizeof(int));
If the allocation was successful then the old array is freed
free(list);
and the address of the new array is assigned again to the pointer list.
list = tmp;
That is now the two pointers list and tmp point to the same dynamically allocated array. You can use either pointer to free the allocated memory but logically it is better to use the pointer list because the program simulates reallocation an array initially pointed to by the pointer list.

Related

Trying to free reallocated memory gives free(): invalid pointer

I can't figure out why I am getting the error free(): invalid pointer when running this code. I thought p is going to point to a block of memory set aside for the structures, so I am trying to free pointers beginning from the p e.g. p+1, but this is no good. What am I missing here?
#include <stdio.h>
#include <stdlib.h>
struct s {
int x;
};
int main()
{
struct s *p = NULL;
for (int i = 0; i < 3; i++) {
if ((p = realloc(p, (i+1) * sizeof(struct s))) != NULL) {
struct s x = {.x=i*10};
*(p+i) = x;
} else exit(EXIT_FAILURE);
}
for (int i=0;i<3;i++) {printf("%d ", (p+i)->x);}
//free(p);
free(p+1);
//free(p+2);
return 0;
}
Before the loop you declared the pointer p
struct s *p = NULL;
So after the loop it will store the address of the last reallocated memory.
To free the allocated memory you need just to write
free( p );
The expression p + 1 points to the second element of the dynamically allocated array that was not allocated dynamically. It is the whole array that was allocated dynamically.

How to completely delete a dynamic array in C and not just a single element

I have to make a function to delete an entire dynamic array, and I'm having trouble thinking what to do with the data that is stored, because if I just use free() I'd be losing memory.
I couldn't find any help in other issues because they mostly talk about deleting a single element, but I want to destroy the array basically.
Thanks
The rule of thumb is for every malloc there should be a free.
If it's an array, all the data is stored directly in the array's memory. Freeing the array frees all the elements.
For example, let's say I have a struct called person.
typedef struct {
int id;
char name[20];
} person;
If I want to store 8 structs, I allocate an array large enough for 8 structs.
person *people = malloc(sizeof(person) * 8);
Each thing I assign to the array is copied to the array.
// `p` uses automatic stack memory which is managed for you
person p = { .id = 23, .name = "Yarrow Hock" };
people[0] = p; // p is copied to the array's heap memory
When I'm done, I free the array. This frees all the structs.
free(people);
One malloc, one free.
An array of pointers is different. If I want to store an array of 8 pointers to my struct, I allocate space for 8 pointers.
person **array = malloc(sizeof(person*) * 8);
Then I must allocate space for each element. Only the pointer is copied to the array.
for( int i = 0; i < 8; i++ ) {
person *p = malloc(sizeof(person));
p->id = i;
p->name = "Some One";
people[i] = p;
}
The allocated heap memory for the elements must be managed. How you do that depends on who you decide "owns" the elements.
If it's the array, then the array should free them before freeing itself.
for( int i = 0; i < 8; i++ ) {
free(people[i]);
}
free(people);
If someone else owns the elements, just free the array. Something else will manage the memory of the elements.
free(people);
Which you do depends on how your code is designed. For example, if I store a pointer to each person's name in an array.
char *names = malloc(sizeof(char*));
for( int i = 0; i < 8; i++ ) {
names[i] = people[i]->name;
}
// Free only the array.
free(names);
When I free names I do not free the elements. They are part of memory names does not "own", it has "borrowed" the memory. If I were to free the elements of names then the persons in people would be corrupted.
What if the struct itself has pointers?
typedef struct {
int id;
char *name;
} person;
They need to be free'd as well. This complicates managing the memory of the array's elements. You need to know details of how the array's elements are managed.
for( int i = 0; i < 8; i++ ) {
free(people[i]->name);
free(people[i]);
}
free(people);
Array implementations can deal with this by allowing you to register a function to handle deallocating the elements. For example, GLib Pointer Arrays.
void free_the_people(gpointer data) {
person *p = (person*)data;
printf("Deallocating %s\n", p->name);
free(p->name);
free(p);
}
int main() {
GPtrArray *people = g_ptr_array_new_full(8, free_the_people);
// Allocate memory for the struct.
person *p = malloc(sizeof(person));
// Allocate memory for the string.
p->name = malloc(40);
strcpy(p->name, "Yarrow Hock");
p->id = 23;
// Copy the pointer to the array.
g_ptr_array_add(people, p);
// Call free_the_people on each element, then deallocate the array.
g_ptr_array_unref(people);
}

HEAP CORRUPTION DETECTED memory leak in C

I got and error which says
Debug assertation failed and heat corruption detected
like everything is working good in my program but I get that error. Where is the memory leak here? I have to free that memory in the main because my functions need to return pointers.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int *dynamic_reader(unsigned int n) {
/*making new array and checking if allocation succeeded*/
int *mem;
mem = malloc(n * sizeof(int));
if (!mem) {
printf("Memory allocation failed\n");
exit(-1);
}
/*letting the user to input the values for the array*/
int i = 0;
while (i < n) {
scanf("\n%d", &mem[i]);
i++;
}
/*printing the array just to make sure everything is good*/
for (int j = 0; j < n; j++) {
printf("%d ", mem[j]);
}
return mem;
}
int *insert_into_array(int *arr, unsigned int num, int newval) {
/*making new bigger array*/
int *newarr = realloc(arr, (num + 1) * sizeof(int));
/*adding the integer to this new array */
newarr[num] = newval;
printf("\n");
/*printing to make sure everything is correct*/
for (int j = 0; j < num + 1; j++) {
printf("%d ", newarr[j]);
}
return newarr;
}
int main(void) {
/*In dynamic_reader function I need to make an array which size is given as a parameter*/
/*In this case I choosed 3*/
int *arr = dynamic_reader(3);
int num = 3;
/*In insert_into_array function I need to add one integer to this array I made in dynamic_reader*/
/*The parameters are the array, the number of elements in the array already done and the integer I want to add*/
int *c = insert_into_array(arr, num, 9);
/*I free the memory here because I need to return the pointers of these arrays in the function so it cant be done there*/
free(arr);
free(c);
}
You are double freeing your memory. Check the documentation for realloc. Realloc will either 1) expand the passed buffer or 2) will allocate a new buffer, copy the data, and free the original buffer. When you do:
free(arr);
free(c);
You are double freeing a value that was either once already freed by realloc or already freed by the first free(arr)
Additionally, you should check if realloc fails (returns NULL) and if so, handle the case appropriately.
First you malloc an array, which you return to your main function as arr. Then in another function, you realloc where arr is an argument to the realloc, but some other pointer stores the results. Depending on what happened in realloc, you've either got arr and newarr pointing to the same location, or newarr pointing to a valid location and arr pointing to an invalid location that has been freed. Either way, freeing both of them at the end is a problem.
No need to free(arr), that is taken care of when you realloc() it. The pointer returned by realloc() will either point to memory which includes the original memory, or free the old memory after copying its content to a new, larger chunk of memory.

Free array pointed to by a pointer within a struct in C

I have a stack implemented in dynamic array. Below are some of my functions. When I call stk_reset function, it seems that the stack is not freed completely.
Here is my struct. It is a requirement that I have to have a pointer inside struct pointing to the dynamic array
typedef struct stack {
char *items;
int arrSize;
int top;
} StackStruct;
void stack_create(StackStruct *s) {
char *arr = malloc(sizeof(char)*2);
if (arr == NULL) {
printf("Insufficient memory to initialize stack.\n");
return;
}
s->arrSize = 2;
s->items = arr;
s->top = -1;
}
How do I deallocate each element of the array holding the stack? I used this statement free((s->items)++) with a for loop, but it did not work.
void stk_reset(StackStruct *s) {
int i;
for (i = 0; i <= s->arrSize; i++)
free((s->items)++);
free(s->items);
s->items = NULL;
s->top = -1;
s->arrSize = 0;
}
You can only call free on the pointer returned to you by malloc and you can only free the whole block, not individual bytes.
You want one (1) call to free per call to malloc. Here you've only allocated one item with room for two characters. To free it, it's pretty straight-forward. Here is what is called a "Safe" release (or free).
if (s->items != NULL) {
free(s->items);
s->items = NULL; // Reset to be safe.
}
Though to use this, you will need to make sure you initialize your value to NULL before you try to use it: s->items = NULL;.
No other free calls are required, and certainly not in a loop when you only had one malloc.

Assigning a pointer in a struct to a variable

This program is supposed to create a dynamic memory vector. I'm pretty sure I'm using malloc correctly. My real problem is some syntax with pointers, particularly a pointer inside a struct.
I'm trying to access the address of an int pointer inside a struct so I can assign it to another pointer
My given struct is:
typedef struct{
int *items;
int capacity;
int size;
}VectorT;
and the function I'm trying to get to work is:
int getVector(VectorT *v, int index){
int *p;
p = v->items;//(2)
p -= v->size;
p += index;
return *p;
}
This is supposed to take the address of the items pointer subtract the number of items in the list and add the index of the desired item to the address of p. Then I return what is at the address of p.
I have a pretty strong feeling that line (2) is not the syntax I need.
Depending on what I've tried so far my program either crashes when getVector is called or it outputs (my best guess) some memory locations.
Here's the code that adds a vector:
void addVector(VectorT *v, int i){
if(v->size >= v->capacity){
//allocate twice as much as old vector and set old pointer to new address
v = (VectorT *) malloc(2 * v->capacity * sizeof(VectorT));
if(v == NULL){
fprintf(stderr, "Memory allocation failed!\n");//error catch
}
else{
v->capacity *= 2;//double the reported capacity variable
v->size++;//add one to the reported size variable
v->items =(int *) i;//add the item to the vector (A)<-----
}
}
else{
v->size++;//add one to the reported size variable
v->items =(int *) i;//add the item to the vector (B)<-----
}
}
I don't feel like my problem is in here, but if it is I have some suspicion at lines A & B...
Any insight would be much appreciated, Thanks!
Your dealing with pointers is wrong in at least these places:
The code with the comment "add the item to the vector" is very wrong: instead of adding an item, it overrides the pointer with an arbitrary int.
v->items =(int *) i;
should be
*(v->items) = i;
Your pointer arithmetic is incorrect: subtracting the size and adding an index will get you a pointer prior to the beginning of the allocated area, which is not correct.
You are assigning the results of malloc to a local variable v of type "pointer to vector". This assignment has no effect in the caller, because pointers are passed by value. If you wanted to re-assing the vector in the addVector, you should have taken VectorT **pv as the first parameter. This code fragment does not look right at all: it appears that you should be assigning v->items=malloc(2 * v->capacity * sizeof(int)) instead of v=malloc(...)
You do not free the old vector when you do a malloc, causing a memory leak.
You want the address of i, therefore:
v->items =&i;//add the item to the vector (A)<-----
Also, when calculating the size you'll want:
p -= (v->size*sizeof(int));
UPDATE:
You can also pass a pointer to i into getVector and just save that in v->items
int getVector(VectorT *v, int *index)
//...
v->items = i;
I see you're allocating memory for VectorT when you should be allocating memory for VectorT.items
void addVector(VectorT *v, int i){
if(v->size >= v->capacity){
//allocate twice as much as old vector and set old pointer to new address
v->items
int* tmp = malloc(2 * v->capacity * sizeof(int));
if(tmp == NULL){
fprintf(stderr, "Memory allocation failed!\n");//error catch
}
else{
int j;
for (j = 0; j < v->size; j++){
tmp[j] = v->items[j];
}
free(v->items);
v->items = tmp;
v->capacity *= 2;//double the reported capacity variable
v->items[v->size] = i;//add the item to the vector (A)<-----
v->size++;//add one to the reported size variable
}
}
else{
v->items[v->size] = i;//add the item to the vector (B)<-----
v->size++;//add one to the reported size variable
}
}
int getVector(VectorT *v, int index){
return v->items[index]
}

Resources