Я создал реализацию структуры данных List для универсального типа данных, каждый узел объявлен следующим образом.
struct Node
{
void *data;
....
....
}
Таким образом, каждый узел в моем списке будет иметь указатель на фактический элемент данных (универсальный может быть любым), который должен храниться в списке.
У меня есть следующая подпись для добавления узла в список
AddNode(struct List *list, void* eledata);
проблема в том, что когда я хочу удалить узел, я хочу освободить даже блок данных, указанный * указателем данных внутри структуры узла, которая будет освобождена. сначала освобождение блока данных кажется прямым
free(data) // forget about the syntax.....
Но если данные указывают на блок, созданный malloc, то вышеупомянутый вызов в порядке .... и мы можем освободить этот блок, используя свободную функцию
int *x = (int*) malloc(sizeof(int));
*x = 10;
AddNode(list,(void*)x); // x can be freed as it was created using malloc
что если узел создается следующим образом
int x = 10;
AddNode(list,(void*)&x); // x cannot be freed as it was not created using malloc
Здесь мы не можем вызвать free для переменной x !!!!
Как узнать или реализовать функциональные возможности для динамически размещаемых и статических переменных ..., которые передаются в мой список ...
Заранее спасибо ...
Полная реализация выглядит следующим образом list.h просто содержит прототипы функций.
#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;
}