How to construct universal object linked list in C / C is a good implementation of this
T. W. Burgerthomas Wolfgang Burger Consulting's boss in September 2000
Content: Simplified Problem C Code Solutions C Solution Summary Reference Resources Author
Have you done such a project, which requires you to save a number of different objects in memory? For some cases, the binary tree is the best choice, but in general, a simpler chain list is an obvious choice.
A simplified problem example chain table is difficult to copy the chain list handler to handle different objects, even if the logic is identical. E.g:
Two structures Similar Linches
Struct Struct_Object_a
{
Int a;
INT B;
Struct_Object_a * next;
} Object_a;
Typedef struct struct_object_b
{
Int a;
INT B;
INT C;
Struct_Object_b * next;
} Object_b;
The two structures defined above are only a small difference. Between Object_b and Object_a is only a integer variable. However, in the compiler, they are still very different. You must copy, delete, and search the linked list for each object stored in the linked list. In order to solve this problem, a joint or structure with all three variables can be used, where integer C is not used in all cases. This may become very complicated and will form a bad programming style.
C Code Solution: One of the better solutions for virtual chains is a virtual chain table. The virtual linked list is a list containing only the list pointer. Objects are stored behind the chain table structure. This is true, first assigning memory for the chain table node, then assigns memory to the object, and then assign the memory to the chain table node pointer, as shown below:
An implementation of virtual link structure
Typedef struct liststruct
{
Liststruct * next;
} List, * plist;
PLIST head = null;
PList Addtolist (PLIST Head, Void * Data, Size_t DataSize)
{
Plist newlist = null;
Void * p;
// Assign node memory and data memory
NEWLIST = (PLIST) Malloc (Datasize SizeOf (List));
/ / Specify a pointer for this data buffer
P = (void *) (newlist 1);
// copy data
Memcpy (P, Data, DataSize);
// Specify this node to the header of the list
IF (HEAD)
{
Newlist-> next = head;
}
Else
Newlist-> next = null;
HEAD = newlist;
Return head;
}
The chain table node is now based on the basics of a copy of the data value. This version can handle scalar values well, but cannot handle objects with an element with Malloc or NEW allocation. To handle these objects, the List structure needs to include a general release function pointer, which can be used to release the node from the linked list to release the memory (or turn the file, or call the shutdown method) from the linked list.
A linked list with release functions
Typedef void (* listnodedestructor) (void *);
Typedef struct liststruct
{
ListNodedestructor DestructFunc;
Liststruct * next;
} List, * plist; plist addtolist (PLIST head, Void * Data, Size_t DataSize,
ListNodedestructor Destructor)
{
Plist newlist = null;
Void * p;
// Assign node memory and data memory
NEWLIST = (PLIST) Malloc (Datasize SizeOf (List));
/ / Specify a pointer for this data buffer
P = (void *) (newlist 1);
// copy data
Memcpy (P, Data, DataSize);
Newlist-> deStructFunc = Destructor;
// Specify this node to the header of the list
IF (HEAD)
{
Newlist-> next = head;
}
Else
Newlist-> next = null;
HEAD = newlist;
Return head;
}
Void deletelist (PLIST HEAD)
{
PLIST NEXT;
While (Head)
{
NEXT = head-> next;
Head-> deStructFunc ((void *) head);
Free (Head);
HEAD = NEXT;
}
}
Typedef struct listdatatruct
{
LPSTR P;
} List_data, * plist_data;
Void ListDataDestructor (void * p)
{
/ / Type to the node pointer
PLIST PL = (PLIST) P;
// Type conversion for the data pointer
PLIST_DATA PLD = (PLIST_DATA) (PL 1);
Delete PLD-> P;
}
PLIST head = null;
void testlist ()
{
PLIST_DATA D = New List_Data;
D-> p = new char [24];
STRCPY (D-> P, "Hello");
Head = addtolist (head, (void *) d, sizeof (plist_data),
ListDataDestructor;
/ / The object has been copied, and now deletes the original object.
Delete D;
D = new list_data;
D-> p = new char [24];
STRCPY (D-> P, "world");
Head = addtolist (head, (void *) d, sizeof (plist_data),
ListDataDestructor;
Delete D;
// Release the list
Deletelist (HEAD);
}
The same pointer containing the same release function in each chain table node seems to be a waste of memory space. This is true, but only the linked list always contains the same object to belong to this. Writing a list in this way allows you to place any object anywhere in the linked list. Most linked list functions require objects that are always the same or class. The virtual chain table does not require this. It is only a method of separating objects to each other. To achieve this, you can detect the values of the release function pointer, or you can add a type value before all of which are used in the list and detect it. Of course, if you want to write a chain as a C class, you can only turn once for the settings and storage of pointers to the release function.
C solution: Class link list This solution defines a CLIST class as a class exported from the List structure, which handles a single storage type by storing a single value of the release function. Note that the added getCurrentData () function, the function completes the mathematical conversion from the chain table node pointer to the data offset pointer. A virtual chain table object
// Define the release function pointer
Typedef void (* listnodedestructor) (void *);
// Dissolve Lin table
Typedef struct ndliststruct
{
NDLISTSTRUCT * NEXT;
} Nd_list, * pnd_list;
// Define the chain class for processing a data type
Class Clist: Public ND_LIST
{
PUBLIC:
Clist (ListNodedestructor);
~ Clist ();
Pnd_list addtolist (void * data, size_t datasize);
Void * getcurrentdata ();
Void deletelist (PND_LIST HEAD);
Private:
PND_LIST M_HEADOFLIST;
PND_LIST M_CURRENTNODE;
ListNodeDestructor M_DestructFunc;
}
// Construct this linked object with the correct start value
CList :: Clist (ListNodedestructor Destructor)
: m_headoflist (null), M_CurrentNode (NULL)
{
m_destructfunc = destructor;
}
// Remove the linked list after the object
Clist :: ~ clist ()
{
Deletelist (m_headoflist);
}
/ / Add a new node to the list
PND_LIST CLIST :: Addtolist (void * data, size_t datasize)
{
PND_LIST NEWLIST = NULL;
Void * p;
// Assign node memory and data memory
NEWLIST = (PND_LIST) Malloc (DataSize SizeOf (ND_LIST));
/ / Specify a pointer for this data buffer
P = (void *) (newlist 1);
// copy data
Memcpy (P, Data, DataSize);
// Specify this node to the header of the list
IF (M_Headoflist)
{
Newlist-> next = m_headoflist;
}
Else
Newlist-> next = null;
M_Headoflist = newlist;
Return M_Headoflist;
}
// Return the current node data as a Void type so that the call function can convert it to any type
void * clist :: getcurrentdata ()
{
Return (void *) (M_CurrentNode 1);
}
// Delete the assigned list
Void Clist :: deletelist (pnd_list head)
{
PND_LIST NEXT;
While (Head)
{
NEXT = head-> next;
m_destructfunc ((void *) head);
Free (Head);
HEAD = NEXT;
}
}
// Create a structure to create and store it in the list
Typedef struct listdatatruct
{
LPSTR P;
} List_data, * pnd_list_data;
/ / Define Standard Release Function
Void ClassListDataDestructor (void * p) {
/ / Type to the node pointer
PND_LIST PL = (PND_LIST) P;
// Type conversion for the data pointer
PND_LIST_DATA PLD = (PND_LIST_DATA) (PL 1);
Delete PLD-> P;
}
// Test the code above
void myclistclasstest ()
{
// Create a list class
CLIST * PA_LIST_OF_DATA = New Clist (ClassListDataDestructor);
// Create a data object
PND_LIST_DATA D = New List_Data;
D-> p = new char [24];
STRCPY (D-> P, "Hello");
// Create a partial pointer to the top of the list
PND_LIST HEAD = NULL;
/ / Add some data to the list
HEAD = pa_list_of_data-> addtolist (void *) D,
SIZEOF (PND_LIST_DATA);
/ / The object has been copied, and now deletes the original object.
Delete D;
// Confirm that it has been stored
Char * p = ((pnd_list_data) pa_list_of_data-> getCurrentData ()) -> P;
D = new list_data;
D-> p = new char [24];
STRCPY (D-> P, "world");
Head = pa_list_of_data-> addtolist (void *) D, SIZEOF (PND_LIST_DATA));
/ / The object has been copied, and now deletes the original object.
Delete D;
// Confirm that it has been stored
P = ((pnd_list_data) pa_list_of_data-> getCurrentData ()) -> P;
/ / Delete the list class, the destructor will delete the list
DELETE PA_LIST_OF_DATA;
}
Summary From the previous discussion, it seems that only a simple list is to do a lot of work, but this must only be done. It is easy to expand this code into a C class that handles sort, search, and various other tasks, and this class can process any data objects or classes (in one project, which process about twenty different objects). You will never have to reply this code.
Reference resource
The Linux C Programming Lists is designed to help people use the C language Linux programming, including many links to mailing lists, common questions, tutorials, and other content links. Microsoft Foundation Class provides similar features in its CLIST class. The CLIST in the MFC and other types of requirements or classes can only be a type. The programmer does not have control over the code, which is different from zero.