struct Link
{
frame_t *frame;
struct Link *next;
} typedef link_t;
Inside I allocate memory for frame_t
I tried recursively freeing it but the program crashed when I ran it.
struct Frame
{
char *name;
unsigned int duration;
char *path;
} typedef frame_t;
And inside of that I allocate memory for name and path.
void freeFrames(link_t** head)
{
if (*head != NULL)
{
if ((*head)->next != NULL)
{
free((*head)->frame->name);
free((*head)->frame->path);
free((*head)->frame);
freeFrames(&((*head)->next));
}
free(*head);
}
}
How can I free memory for this?
Have you initialised the pointers correctly? If you did not assign a concrete value to them, you must initialise them to NULL.
You cannot free a null pointer, so you should check: if(name) free(name);
You cannot free string literals! So if you do name = "hello", your program is guaranteed to fail if trying to do so.
Additionally, you have a memory leak (stole that one from n.m.'s comment...):
if ((*head)->next != NULL)
{
free((*head)->frame->name);
free((*head)->frame->path);
free((*head)->frame);
// ^ you will only free, if there is a successor node!
// so you won't free them on the last node!
freeFrames(&((*head)->next));
}
It should be (not having added the NULL checks so far!):
if(*head)
{
free((*head)->frame->name);
free((*head)->frame->path);
free((*head)->frame);
if ((*head)->next != NULL)
{
freeFrames(&((*head)->next));
}
free(*head);
}
Additionally: You do not assign anything to your head (*head = NULL;), so why do you have a double pointer?
void freeFrames(link_t* head);
would suffice...
And there is no need for recursion, you simply can advance the pointer as long as there is any:
void freeFrames(link_t* head)
{
while(head)
{
// free members, don't forget the NULL checks
link_t* tmp = head;
head = head->next;
free(tmp);
}
}
Related
I am studying the following C code:
typedef struct msg *m_;
struct msg
{
long from;
long to;
m_ link;
};
m_ queue;
I would like to see an example that explains the role of the pointer, i.e. m_, of the structure inside the structure itself m_ link!
Thank you very much.
To be pedantic: link is a pointer. m_ is not a pointer, it's a typedef. It is used to avoid the need to say "struct msg* link;" inside the struct definition.
As answered in the comment above, the queue is represented by a pointer to the first item, which has a pointer to the second (if any), and so on until you reach a NULL pointer.
It's important to take care when building such lists that no node points to itself or to any precursor, or you get an infinite loop chasing to the tail.
Pointers to the structure type inside the structure itself are very often used for linked lists, trees, etc. In your example, it is referring to a queue implementation.
Here is a very minimal example of a stack implementation using a linked list. The functions require the address of a stack pointer, and an empty stack is a NULL pointer.
struct linked_stack
{
int data;
struct linked_stack *next;
};
void linked_stack_push(linked_stack **stck, int data)
{
struct linked_stack *node = malloc(sizeof(struct linked_stack));
if (node != NULL)
{
node->data = data;
node->next = *stck;
}
*stck = node;
}
int linked_stack_top(linked_stack **stck)
{
if (*stck != NULL)
return (*stck)->data;
return 0; /* stack is empty */
}
void linked_stack_pop(linked_stack **stck)
{
struct linked_stack *node = *stck;
if (*stck != NULL)
{
*stck = node->next;
free(node);
}
}
Example usage:
int main(void)
{
struct linked_stack *stack = NULL;
linked_stack_push(&stack, 10);
printf("top of stack = %d\n", linked_stack_top(&stack));
linked_stack_pop(&stack);
return 0;
}
When I try to free an allocation in a struct inside a struct, I get an error.
How can I fix it?
typedef struct card
{
char* sign;
char* color;
int number;
char* name;
}card;
typedef struct deck
{
card data;
deck* next;
}deck;
deck* deleteHead(deck* head)
{
deck* curr = head;
if (head==NULL)
return head;
curr=curr->next;
if(head->data.color!=NULL)
free(head->data.color);//error
if(head->data.name!=NULL)
free(head->data.name);//error
if(head->data.sign!=NULL)
free(head->data.sign);//error
free(head);//ok
return curr;
}
when I'll delete the errors and only freeing the head - it'll work, but when I'll try to delete the allocations inside the head, I'll get a run time error.
How can I solve this?
Thank you in advance.
You probably did not initialize the pointers in the card structure. These should either be initialized to NULL or to a pointer to memory allocated by malloc, calloc or strdup.
Also note that you don't need to test pointers against NULL before calling free(). free(NULL); will gracefully return immediately, it is legal to call free with NULL. Incidentally it is also legal in C++ to delete a null pointer.
The function can be further simplified this way:
deck *deleteHead(deck *head) {
deck *next = NULL;
if (head != NULL) {
next = head->next;
free(head->data.color);
free(head->data.name);
free(head->data.sign);
free(head);
}
return next;
}
The function free can only de-allocate a block of memory previously allocated by a call to malloc, calloc or realloc. Your code will run without any runtime error if you initialize it properly. Here's a sample code:
int main()
{
deck* root = (deck*)malloc(sizeof(struct deck));
root->card.color = strdup("color");
root->card.name = strdup("name");
root->card.sign = strdup("sign");
root->card.number = 2;
root->next = NULL;
root = deleteHead(root);
return 0;
}
And also there is a slight correction in your code:
typedef struct deck
{
card data;
struct deck* next;
}deck;
I have created a linked list in C that is used to store data which is then modified as required. In creating the linked list I have used the following
struct car_elements
{
char car_rego[7];
double time_parked;
struct car_elements *next;
};
typedef struct car_elements car;
/* Defined as global variable to hold linked list */
car *head = NULL;
car *SetupCars()
{
car *ptr = head;
car *new_car = NULL;
new_car = (car*) malloc(sizeof(car));
if (!new_car)
{
printf("\nUnable to allocate memory!\n");
exit(1);
}
strcpy(new_car->car_rego, "empty");
new_car->time_parked = time(NULL);
new_car->next = NULL;
if (ptr == NULL)
{
return (new_car);
}
else
{
while (ptr->next)
{
ptr = ptr->next;
}
ptr->next = new_car;
return (head);
}
}
From main I call the following to create the linked list
for(int i = 0; i<TOTAL_CARS; i++) {
head = SetupCars(head);
}
The problem is that now I have a memory leak - Is there a better way to create a fixed size linked list. At the end of the program running I can
free(head);
However I cannot call within SetupCars method
free(new_car);
I could create new_car as a global variable I guess and free it at the end of the program but I cannot help but feel there is a better way to do it. I don't think global variables are evil if used properly however I would appreciate some advice.
WHy not just free it at the end? SOmething like this:
car *tofree;
car *ptr = head;
while(ptr) {
tofree = ptr;
ptr = ptr->next;
free(tofree);
}
You need a function to free the entire list, like:
void free_cars(car*p) {
while (p != NULL) {
car* nextp = p->next;
free (p);
p = nextp;
}
}
So you would call
free_cars (head);
head = NULL;
Perhaps even by having a macro
#define DELETE_CARS(CarsVar) do { \
free_cars(CarsVar); CarsVar = NULL; } while(0)
then just write DELETE_CARS(head); later in your code.
And indeed, manual memory management is painful, you need to avoid memory leaks. Tools like valgrind can be helpful. And you could consider instead to use Boehm's garbage collector, so use GC_MALLOC instead of malloc and don't bother freeing memory.... Read more about garbage collection.
Keep car *head as a global var. For SetupCars:
void SetupCars() /* void will do, unless you want a copy of the new "car" */
{
car *new_car = NULL;
new_car = malloc(sizeof *new_car); /* don't need to cast return value of malloc */
/* do checks and setup new_car... */
if (head == NULL) /* first element */
{
head = new_car;
}
else /* easier to add new_car as the FIRST element instead of last */
{
new_car->next = head;
head = new_car;
}
}
From main you create the linked list the same way:
for(int i = 0; i<TOTAL_CARS; i++) {
SetupCars(); /* without any arguments */
}
Then at the end, you loop through the list and free the objects. As Manoj Pandey posted in his answer:
car *tofree;
car *ptr = head;
while(ptr) {
tofree = ptr;
ptr = ptr->next;
free(tofree);
}
Consider the following code snippet
struct node {
char *name;
int m1;
struct node *next;
};
struct node* head = 0; //start with NULL list
void addRecord(const char *pName, int ms1)
{
struct node* newNode = (struct node*) malloc(sizeof(struct node)); // allocate node
int nameLength = tStrlen(pName);
newNode->name = (char *) malloc(nameLength);
tStrcpy(newNode->name, pName);
newNode->m1 = ms1;
newNode->next = head; // link the old list off the new node
head = newNode;
}
void clear(void)
{
struct node* current = head;
struct node* next;
while (current != 0)
{
next = current->next; // note the next pointer
/* if(current->name !=0)
{
free(current->name);
}
*/
if(current !=0 )
{
free(current); // delete the node
}
current = next; // advance to the next node
}
head = 0;
}
Question:
I am not able to free current->name, only when i comment the freeing of name, program works.
If I uncomment the free part of current->name, I get Heap corruption error in my visual studio window.
How can I free name ?
Reply:
#all,YES, there were typos in struct declaration. Should have been char* name, and struct node* next. Looks like the stackoverflow editor took away those two stars.
The issue was resolved by doing a malloc(nameLength + 1).
However,If I try running the old code (malloc(namelength)) on command prompt and not on visual studio, it runs fine.
Looks like, there are certain compilers doing strict checking.
One thing that I still do not understand is , that free does not need a NULL termination pointer, and chances to overwrite the allocated pointer is very minimal here.
user2531639 aka Neeraj
This is writing beyond the end of the allocated memory as there is no space for the null terminating character, causing undefined behaviour:
newNode->name = (char *) malloc(nameLength);
tStrcpy(newNode->name, pName);
To correct:
newNode->name = malloc(nameLength + 1);
if (newNode->name)
{
tStrcpy(newNode->name, pName);
}
Note calling free() with a NULL pointer is safe so checking for NULL prior to invoking it is superfluous:
free(current->name);
free(current);
Additionally, I assume there are typos in the posted struct definition (as types of name and next should be pointers):
struct node {
char* name;
int m1;
struct node* next;
};
In brief, I am attempting to use a void pointer as a parameter to a function pointer, but am getting the compiler error "invalid use of void expression".
I have a doubly linked list (DLL) whose node structure is as follows:
typedef struct DL_LIST
{
uint16 tag; /* Object ID tag */
struct DL_LIST *previous;
struct DL_LIST *next;
void *object; /* A pointer to this node's object */
uint32 size; /* The size of this node's object, in bytes */
} DL_LIST;
I also have the following function which is used to delete a single such node:
void dl_delete(DL_LIST *node, void (*dl_destructor)(void*)) {
if (node != NULL) {
dl_extract(node); /* Removes the node from the list */
if (node->object != NULL) {
(*dl_destructor)(node->object);
free(node->object);
}
free(node);
}
}
where the node extraction function is:
DL_LIST *dl_extract(DL_LIST *node) {
if (node != NULL) {
if (node->previous != NULL) {
node->previous->next = node->next;
}
if (node->next != NULL) {
node->next->previous = node->previous;
}
node->previous = NULL;
node->next = NULL;
}
return node;
}
The idea here is to be able to pass a separate destructor function for each type of object that may be stored in a node. This destructor function takes a pointer to the object as a parameter, and is used to free any heap memory that is being used by children of the object.
The aforementioned error occurs when I try to call dl_delete() from a function designed to delete an entire DLL:
void dl_destroy(DL_LIST **list, void (*dl_destructor)(void*)) {
DL_LIST *marker;
DL_LIST *previous_node;
if (*list != NULL) {
previous_node = (*list)->previous;
while (previous_node != NULL) {
marker = previous_node->previous;
dl_delete(previous_node, (*dl_destructor)(previous_node->object));
previous_node = marker;
}
/* Code removed for brevity */
}
}
I have read this introduction to function pointers, but am still unable to determine how to remedy the problem. An explanation of what I am doing wrong would be most appreciated.
this line
dl_delete(previous_node, (*dl_destructor)(previous_node->object));
needs to be dl_delete(previous_node, dl_destructor);
also in dl_delete this line (*dl_destructor)(node->object);
should be dl_destructor(node->object);
also, just for safety, I like to check that my function pointers are not null before trying to make a call using them
so in dl_delete something like :-
if(dl_destructor!=NULL) dl_destructor(node->object);