Hi
I have created a List data structure implementation for generic data type with each node declared as following.
struct Node
{
void *data;
....
....
}
So each node in my list will have pointer to the actual data(generic could be anything) item that should be stored in the list. I have following signature for adding a node to the list
AddNode(struct List *list, void* eledata);
the problem is when i want to remove a node i want to free even the data block pointed by *data pointer inside the node structure that is going to be freed. at first freeing of datablock seems to be straight forward
free(data) // forget about the syntax.....
But if data is pointing to a block created by malloc then the above call is fine....and we can free that block using free function
int *x = (int*) malloc(sizeof(int));
*x = 10;
AddNode(list,(void*)x); // x can be freed as it was created using malloc
what if a node is created as following
int x = 10;
AddNode(list,(void*)&x); // x cannot be freed as it was not created using malloc
Here we cannot call free on variable x!!!!
How do i know or implement the functionality for both dynamically allocated variables and static ones....that are passed to my list....
Thanks in advance...
The complete implementation is as following list.h simply contains function prototypes.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include "list.h"
//structure of each node
static struct Node{
void *Data;
struct Node * Next;
struct Node * Prev;
};
//complete list interface
struct List{
int Size;
struct Node DummyNode; //dummy node
void (*Print)(void *Data);
};
//create new List
struct List * CreateList(void(*Print)(void* Data)){
struct List *newList = (struct List *)malloc(sizeof(struct List));
if(newList != NULL){
newList->DummyNode.Data = NULL;
newList->DummyNode.Next = newList->DummyNode.Prev = &newList->DummyNode;
newList->Size = 0;
newList->Print = NULL;
if(Print != NULL) newList->Print = Print; // hook to user provided print function
return newList;
}
return NULL;
}
//Node *ptr point to one node before the actual node to be removed
static void _RemoveNode(struct List *list, struct Node *ptr)
{
struct Node *temp = ptr->Next; //catch hold of node that is to be removed
ptr->Next = temp->Next; // link previous node's next pointer with the temp node next pointer
temp->Next->Prev = ptr; // link next node's previous pointer with previous node pointer
temp->Prev = NULL; // unlink from previous node
temp->Next = NULL; // unlink from next node
free(temp->Data); // free the data ............ !!! need to mode generic before cleaning the resource
free(temp); // remove the node itself.
list->Size--;
}
void RemoveNodeAt(struct List *list,int nodeIndex)
{
if( list->Size > 0 && (nodeIndex >= 0 && nodeIndex < list->Size)){
int i=-1; // meaning we are at dummy node
struct Node *ptr = NULL;
for(ptr = &list->DummyNode ;i < nodeIndex - 1 ;i++) // traverse up to one node before the actual node
ptr = ptr->Next;
_RemoveNode(list,ptr);
}
}
//Node *ptr point to one node before the actual node to be removed
static void _AddNode(struct List *list, struct Node *ptr,void *data)
{
//create New Node
struct Node *newNode = (struct Node*)malloc(sizeof(struct Node));
if(newNode != NULL){
newNode->Data = data;
//shift node at index to right
newNode->Next = ptr->Next;
newNode->Prev = ptr;
ptr->Next = newNode;
newNode->Next->Prev = newNode;
list->Size++;
}
}
void AddNodeAt(struct List *list,int nodeIndex,void *data)
{
//A node can be added just before head and just after tail.
if( nodeIndex >= 0 && nodeIndex <= list->Size){
int i=-1; // meaning we are at dummy node
struct Node *ptr = NULL;
for(ptr = &list->DummyNode ;i < nodeIndex - 1 ;i++) // traverse up to one node before the actual node
ptr = ptr->Next;
_AddNode(list,ptr,data);
}
}
void RemoveNode(struct List *list)
{
if(list->Size > 0){ //check if the list is not empty
struct Node * temp = list->DummyNode.Prev; //catch hold of last node
temp->Prev->Next = temp->Next; //establish previous node's next pointer to temp node next pointer
temp->Next->Prev = temp->Prev; //establish next node's previous pointer to temp node previous pointer
temp->Next = NULL; // unlink temp node from next node
temp->Prev = NULL; // unlink temp node from previous node
free(temp->Data); // free the data ............ !!! need to mode generic before cleaning the resource
free(temp); // remove the node itself.
list->Size--;
}
}
void AddNode(struct List *list,void *data)
{
struct Node *ptr = list->DummyNode.Prev;
//create New Node
struct Node *newNode = (struct Node*)malloc(sizeof(struct Node));
if(newNode != NULL){
newNode->Data = data;
//shift node at index to right
newNode->Next = ptr->Next;
newNode->Prev = ptr;
ptr->Next = newNode;
newNode->Next->Prev = newNode;
list->Size++;
}
}
void DeleteAllNodes(struct List *list)
{
struct Node *ptr = &list->DummyNode;
while(list->Size > 0){
_RemoveNode(list,ptr);
ptr = ptr->Next;
}
}
void Display(struct List *list)
{
if(list->Print != NULL){ //If conusmer doesnot provide a print function just give up printing process.
int i=0;
struct Node *ptr = &list->DummyNode;
for(i = 0; i < list->Size; i++){
ptr = ptr->Next;
list->Print(ptr->Data); // let the consumer of the list data structure print the way he wants
}
}
}
// must be used before inserting automatic variables are passed in to the list
// because freeing a automatic variable with free function is a crime....!!!! *(~_~)*
// So i want you to create clones of the automatic variables and pass those variables.
// AddNode(list,Clone(&i,sizeof(i)));
void * Clone(void *data, int size)
{
void * clone = malloc(size);
memcpy(clone,data,size);
return clone;
}