I have in the existing source base, linked list implementation(adding node, insertion, deletion , traversal) for the following structure:
typedef struct tagDirInfo
{
char *pdirName;
struct tagDirInfo *__next;
struct tagDirInfo *__prev;
}DIR_HEADER;
Lets assume that char* pdirName points to the data part
I want to form a wrap up for the data part and reuse the existing APIs and so that, the new linked list structure has the data part as:
typedef struct printJob
{
char labelName[BUF_LEN];
int priStatus;
time_t time_stamp;
}PRINTJOB;
I think if I do something like:
PRINTJOB newJob;
/* Fill in newJob structure */
DIR_HEADER *newNode;
newNode->pdirName = (char*)newJob;
newNode->__next = NULL;
newNode->__prev = NULL;
Doing so, will fill in the linked list structure.
But how can I access labelName data field through pdirName field of the linked list structure?
Do you mean you want do something like :
printf("labelName : %s\n", ((PRINTJOB *)(newNode->pdirName))->labelName);
However, your code have one mistake! To correct it:
Change
newNode->pdirName = (char*)newJob;
to
newNode->pdirName = (char*)&newJob;
You should use templates (if you could use c++).
char* Labelname = ((PRINTJOB*) newNode->pdirName)->labelName;
By the way, "newJob" should be of type PRINTJOB* not PRINTJOB.
A better solution would be following:
typedef struct _LINKED_LIST {
struct _LINKED_LIST *_Next;
struct _LINKED_LIST *_Prev;
} LINKED_LIST;
typedef struct {
LINKED_LIST List;
char labelName[BUF_LEN];
int priStatus;
time_t time_stamp;
} MY_LINKED_LIST_DATA;
MY_LINKED_LIST_DATA* MyData = (MY_LINKED_LIST_DATA*)
malloc(sizeof(MY_LINKED_LIST_DATA));
MyData->List->_Next = NULL;
MyData->List->_Prev = NULL;
Your data always contains linked list specific fields _Next and _Prev.
Related
I'm currently working on a project that require me to use some linked lists.
I'm used to them but I really don't like the fact that I need to duplicate my code.
Here is what i mean :
struct A {
struct A *prev;
struct A *next;
int i;
}
struct B {
struct B *prev;
struct B *next;
char *str;
}
If I want to create a function that add an element to any of my liked list i would need to do something like :
void add_A_element(struct A *list, struct A *new_element) { [...] }
void add_B_element(struct B *list, struct B *new_element) { [...] }
Here is my question, is there a way for me to have only one function for all my structures ?
I'm wondering if i could do so with an other structure like :
struct template {
struct template *prev;
struct template *next;
}
Then the function to add my element would look like :
void add_element(void *list, void *new_element)
{
struct template tmp_list = (struct template *)list;
struct template tmp_new_element = (struct template *)new_element;
for (struct template tmp = tmp_list; tmp != NULL; tmp = tmp->next) {
if (tmp->next == NULL) {
tmp->next = tmp_new_element;
tmp_new_element->prev = tmp;
break;
}
}
return;
}
Because we modify the same memory space, i guess this could work but i think some unexpected issue could happen.
I'm wondering if something that looks like a bit more like C++ template could exist in C.
Any help would be appreciate. Thanks
Edit : I managed to do it. I'm still planning on adding few things such as fifo/lifo queue but you can already get it on my Github
I've got full solution with templates (macro) in C if you'd like to have a look, links in the end. Meanwhile, let me explain how to approach that problem:
You should use container_of strategy to abstractly traverse a linked list.
struct linked_list_head
{
struct linked_list_head * next;
struct linked_list_head * prev;
};
struct my_type {
...
struct linked_list_head head;
}
Then the code to get the next would be
struct linked_list_head next(struct linked_list_head * current) {
return current->next;
}
struct my_type next = container_of(next(¤t.head), struct my_type, head));
What is the container_of macro?
Understanding container_of macro in the Linux kernel
If you want to see a full solution using templates implemented, I got a free to use (at your own risk) solution:
The library: https://github.com/flplv/fl-lib/blob/master/headers/linked_list.h
The Usage: https://github.com/flplv/fl-lib/blob/master/tests/test_linked_list.cpp
I'm attempting to refactor some code, to reduce duplication.
This is a curated example, currently defined in each .c file.
struct hrentry_t
{
int custom1;
int custom2;
int custom3;
struct hrentry_t *prev, *next;
};
struct hrentry_t*
attachentry(struct hrentry_t* hentry)
{
struct hrentry_t* hnew = calloc(sizeof(struct hrentry_t), 1);
if (hnew == NULL)
return NULL;
if (hentry != NULL) {
while (hentry->next != NULL) {
hentry = hentry->next;
};
hentry->next = hnew;
hnew->prev = hentry;
}
return hnew;
}
https://github.com/techzilla/check_snmp_extras, is the entire codebase.
I'm declaring and initializing a custom double linked list, and corresponding allocate function. If I moved the linked list functions and code to the common lib .c and .h, how can I get the file specific data inside of each list entry? Each file requires different types and number of variables.
Maybe I make a the double linked list contain only prev next and data? Then somehow make data a handle to an incomplete struct? How would then that need to be allocated though? I'm open to fully reconsidering my approach, so solid advice from experienced coders is always appreciated.
One approach is to make your specialized list data types castable to a generic double-linked list structure. This can be accomplished by putting the non-specialized data members at the beginning of the structure:
struct node_t {
struct node_t * prev, * next;
};
struct hrentry_t
{
struct node_t node;
int custom1;
int custom2;
int custom3;
};
It then makes sense to cast an hentry_t* to a node_t*. The signature of your attachment function becomes:
struct node_t* attachentry(struct node_t* node);
And to use it, you cast instances of your specialized type to the generic type:
struct hentry_t * my_hentry_ptr; /* initialized somehow... */
my_list = attachentry((struct node_t*)my_hentry_ptr);
you are returning hnew if there is already a linked list present rather than the previous list with hnew added onto the tail of it.
return hrentry;
try this
I have to create a struct for a map in C that contains a char* key and void* value which are stored together internally. Rather than having a linked list as an external struct, I have to allocate memory for a linked list cell which contains the link pointer, the key string, and the value together (contiguous).
The key and value data have to be stored directly in the cell and the cell has to be constructed at runtime. I get the beginning of this which would involve a struct like:
struct example {
int count_of_list_elem;
void *list;
}
But I don't know how this is possible w/o using another struct to form the linked list?
Would I have to create some cell within the struct itself, allocate memory to it and pass it three values? I'm just not sure how it would work.
EDIT: I need to use a void* array.
This is a standard way of handling dynamically sized structures in C:
struct example {
struct example *next; /* linked list */
int count_of_list_elem;
char data[1];
}
struct example *bigone = malloc (sizeof (struct example) + 10000);
if (!bigone)
// error
bigone -> next = NULL;
bigone -> count_of_list_elem = 10000;
memcpy (bigone -> data, <data source>);
You can declare a struct before you define it, so that you can refer to it within the struct itself:
typedef struct tagMyStruct* my_struct_pointer;
typedef struct tagMyStruct
{
char* KeyPtr;
void* ValuePtr;
my_struct_pointer NextPtr;
} my_struct;
static my_struct_pointer _listHeadPtr = NULL;
my_struct_pointer AddNewCellToList(char* keyPtr, void* valuePtr)
{
my_struct_pointer newCellPtr = malloc(sizeof(my_struct));
newCellPtr->KeyPtr = keyPtr;
newCellPtr->ValuePtr = valuePtr;
newCellPtr->NextPtr = _listHeadPtr;
_listHeadPtr = newCellPtr;
return(newCellPtr);
}
You will need to malloc appropriate storage for the Key and Value before calling AddNewCellToList.
You can refer to a struct type within its own definition:
struct example {
int count_of_list_elem;
void *list;
struct example *next;
}
Your handle on the whole linked list is just a pointer to the first element:
struct example *head;
You will want to be careful when you create a new node to initialize its next pointer to NULL to indicate that there are (initially) no elements after it.
I am a C beginner with quite a lot of OOP experience (C#) and I am having trouble understanding how some notion of "polymorphism" can be achieved in C.
Right now, I am thinking how to capture the logical structure of a file system using structs. I have a folder that contains both folders and files. Folders in this folder can contain another files and folders, etc.
My approach:
typedef enum { file, folder } node_type;
struct node;
typedef struct {
node_type type;
char *name;
struct node *next;
struct node *children;
} node;
Is this the best I can do? I have found a lot of posts on "polymorphism in C", but I would like to see how a polymorphic data structure like this can be built cleanly and efficiently (in terms of memory wasted on unused members of those structures).
Thanks.
I hope I understand what you want - I'm unsure but I guess you want to do something like that:
typedef struct
{
int type; // file or folder?
} Item;
typedef struct
{
struct A;
// data related to a file
} File;
typedef struct
{
struct A;
// data related to a folder - like pointer to list of Item
} Folder;
As long as both structure follow the same memory mapping (same variables) and adds to it as a child, you'll be able to use the pointer properly in both structs.
Check this one out as well: How can I simulate OO-style polymorphism in C?
Edit: I'm not sure about the syntax above (took it from the link above). I'm used to writing it this way instead:
typedef struct
{
int type;
// data for file
} File;
typedef struct
{
int type;
// data for folder - list, etc
} Folder;
C has no intrinsic notion of polymorphism.
You will end up implementing the mechanisms that you want from scratch. That's not a bad thing. It gives you a lot more flexibility. For example, C++ virtual methods are hard-wired per class, you can't change method pointers per-instance.
Here are a few ideas:
Your node_type field provides a way to do a runtime type query. Going further, you can pack multiple types into one struct using a discriminated (or tagged) union: http://en.wikipedia.org/wiki/Tagged_union. I'm not sure whether a variant type qualifies as OO though.
Polymorphism is usually about behavior. You could store function pointers ("methods") in the struct, with pointers to different functions providing different behavior for different object instances. The C++ way of doing things is for each class to have a table of function pointers, then each object instance references the table for its class (incidentally the table pointers can also play the role of your node_type for RTTI). This is called a virtual method table.
Data inheritance means that subclasses contain all of the base class' data members plus some extra stuff. In C the easiest way to do this is by embedding the base class struct at the head of the derived class struct. That way a pointer to derived is a pointer to base.
typedef struct BaseClass {
int baseMember;
} BaseClass;
typedef struct DerivedClass {
BaseClass base;
int derivedMember;
} DerivedClass;
You could do worse than read "Inside the C++ Object Model" by Stanley B. Lippman. For example, this will help if you want to get an idea of how to implement multiple inheritance.
Here's an illustration of old-school C polymorphism, based on ancient memories of X/Motif.
If you just want a discriminated union (or even just a typed structure with a child pointer that may be null), it's probably simpler in your case.
enum NodeType { TFile, TFolder };
struct Node {
enum NodeType type;
const char *name;
struct Node *next;
};
struct FileNode {
struct Node base_;
};
struct FolderNode {
struct Node base_;
struct Node *children;
/* assuming children are linked with their next pointers ... */
};
Here are the constructors - I'll leave populating the linked lists as an exercise for the reader ...
struct Node* create_file(const char *name) {
struct FileNode *file = malloc(sizeof(*file));
file->base_.type = TFile;
file->base_.name = name; /* strdup? */
file->base_.next = NULL;
return &file->base_;
}
struct Node* create_folder(const char *name) {
struct FolderNode *folder = malloc(sizeof(*folder));
folder->base_.type = TFolder;
folder->base_.name = name;
folder->base_.next = NULL;
folder->children = NULL;
return &folder->base_;
}
Now we can walk a hierarchy, checking the type of each node and responding appropriately. This relies on the first member subobject having zero offset to the parent - if that doesn't hold (or you need multiple inheritance), you have to use offsetof to convert between base and "derived" types.
void walk(struct Node *root,
void (*on_file)(struct FileNode *),
void (*on_folder)(struct FolderNode *))
{
struct Node *cur = root;
struct FileNode *file;
struct FolderNode *folder;
for (; cur != NULL; cur = cur->next) {
switch (cur->type) {
case TFile:
file = (struct FileNode *)cur;
on_file(file);
break;
case TFolder:
folder = (struct FolderNode *)cur;
on_folder(folder);
walk(folder->children, on_file, on_folder);
break;
}
}
}
Note that we have a sort-of-polymorphic base type, but instead of switching on the type enumeration we could have a more completely polymorphic setup with virtual functions. Just add a function pointer to Node, something like:
void (*visit)(struct Node *self,
void (*on_file)(struct FileNode *),
void (*on_folder)(struct FolderNode *));
and have create_file and create_folder set it to an appropriate function (say, visit_file or visit_folder). Then, instead of switching on the enumerated type, walk would just call
cur->visit(cur, on_file, on_folder);
I am a beginner in programming, please go easy on me and I am finding difficult to get the answer for my question. I can't get my head around the complex codes. Can some one please explain me with simple coding of how is generic list manipulation function written which accepts elements of any kind? Thanks in advance.
This is normally done using void pointers:
typedef struct node {
struct node *next;
void *data;
} node;
node *insert(node *list, void *data) {
}
node *delete(node *list, node *to_delete) {
}
such manipulation functions do not depend on the actual type of data so they can be implemented generically. For example you can have a data type struct for the data field above:
typedef struct data {
int type;
void *data;
} data;
/* .... */
data d;
d.type = INT;
d.data = malloc(sizeof(int));
node n = {NULL, (void*)&data);
It looks like you need a heterogenous list. Some pointers below:
Make the data element of the list node as a generic structure, which contains an indicator for data type and data.
/** This should be your data node **/
struct nodedata
{
int datatype;
void *data;
};
/** This should be your list node **/
struct listnode
{
struct nodedata *data;
struct listnode *next;
};
Using the above structure, you can store different types of data.
Use function pointers for comparison functions or invoke different functions depending upon the data type.