Creating a map without using a struct as linked list - c

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.

Related

Is it possible to write a generic traverse function in C for different list structures so long as they contain the "next" field?

First time asking a question but I did look around Google and stackoverflow to see if someone has asked something similar before. In malloc, recasting and free, it looked like the OP asked something similar for example. But it was more complicated.
I was wondering whether it's possible to create a generic function for a list structure in C that traverses the list given that you know that the different types of structures will always have a "next" field.
For example, given these two list-type structures:
typedef struct _list1 {
int value;
list1 *next;
} list1;
typedef struct _list2 {
int value;
char *string;
list2 *next;
} list2;
Is it possible to create a generic void freeList((void *) list) function or something which looks something like the below? I am aware it's a simple thing to write both free functions for each individual list separately.
void freeList((void *) list) {
// Included this because the structs would have different sizes
// so I thought it would be possible to cast it in order to properly dereference the field.
if (sizeof *list == sizeof list1)
*list = (list1) list;
else if (sizeof *list == sizeof list2)
*list = (list2) list;
if (!list) return;
else {
free(list->next);
free(list);
}
}
So far, my experiments with the code shown above didn't fare well given that gcc would complain about dereferencing a void * pointer.
Making a heterogeneous list can be achieved by the use of a tagged union, or just a tag and casting:
struct list_item {
struct list_item *next;
enum datatype type;
void *contents;
};
or
struct list_item {
struct list_item *next;
enum datatype type;
union {
int some_int;
char some_char;
} contents;
};
Then while traversing the list you just have to verify the type stored in type before using the contents of the element.
This check:
if (sizeof *list == sizeof list1)
*list = (list1) list;
else if (sizeof *list == sizeof list2)
*list = (list2) list;
doesn't work because sizeof is a static construct: its value is defined at compilation time. You're just asking for the sizeof void.
is it possible to create a generic function for a list structure in C that traverses the list given that you know that the different types of structures will always have a "next" field.
Yes, as mentioned before; you must be careful that every structure starts with the "next" field; the two structures in your post should therefore be reordered like this:
typedef struct _list1 {
list1 *next;
int value;
} list1;
typedef struct _list2 {
list2 *next;
int value;
char *string;
} list2;
It is not clean code, because the compiler could reorder (and pad) the fields of the structure, but in general it should work.
Is it possible to create a generic void freeList((void) *list) function or something which looks something like...
This is possible if your structs do not refer malloced memory; or they do, but in a uniform (and known) way (note the first case is a sub-case of this last).
If the structs contain pointers pointing to memory that has to be freed, in fact, while freeing the struct the freeList() function should also free the referenced memory. A few solutions come to my mind:
1 - If all the different structs contain the same "pointers" layout, the routine can free those pointers in a uniform manner, knowing in advance what to do. In such scenario, one can also use pointer fields that are not used by all the structs, but only some.
2 - Every single instance of a struct could contain some helper field describing the pointer's layout. For example, just after the "next" field, another "mempntcnt" field could tell how many pointers (to be freed) follow the "next" field. Or, this "mempntcnt" could be passed as a parameter to freeList().
3 - This problem could be managed by a totally separated mechanism, outside the scope of freeList(). Much depends on the final usage: I mean, for a given (kind of) linked list, first call a routine that frees all the memory referenced by the list itself, then free the list by calling the common freeList(). After all, if different structs are needed, then different routines are used on them...
I hope I've been clear enough...
If you ensure that the next pointer is the first member of the struct then this is possible.
typedef struct list1 {
// next pointer must be first
struct list1 *next;
int value;
} list1;
typedef struct list2 {
// next pointer must be first
struct list2 *next;
int value;
char *string;
} list2;
void freeList(void *list) {
if (list) {
freeList(*(void**)list);
free(list);
}
}

Attempting more generic c code, custom data structure, in double linked list, this possible?

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

Define a struct with a member pointing to another member

I'm trying to program a network in C. I have nodes which are linked to each other and I 'd like to do that by making the struct member point to another member (not to another node, because I want to preserve the identity of the links).
The code I made to do that is something like:
struct node{
int k; //number of links
struct node.link **link; //<- wrong
};
but this is not right as node is not a variable but a type of variable (this is already discussed as an error in another QA: first you have to define a variable of node type and then apply the .link, but this doesn't help here). There's also a QA called "Struct member point at another struct member" but they don't do it from definition and it is not so clear how to generalize it (at least for me).
Is it a correct way to do this?
The problem is that the C language doesn't let you create the type you want. You need a type T with the property *T has the same type as T. You can't do that. (Well, function pointers have that property, but that's an irrelevant technicality.)
You have to introduce a new name. C only lets you do this with structs or similar constructions.
struct link {
struct link *ptr;
};
struct node {
int k;
struct link *link;
};
This will get you what you want. Now, in order to go from a struct link * to a struct node *, you'll have to do some pointer math:
struct node *node_from_link(struct link *link) {
return (struct node *) ((char *) link - offsetof(struct node, link));
}
This is also provided by the container_of macro, which is not part of the C standard, but you can find a definition for it online.
Or, you could just go the traditional route.
// Usually easier to do it this way...
struct node {
int k;
struct node *link;
};
Is this what you are after?
struct Node
{
int k; //number of links
void* link;
};
struct Node* create()
{
struct Node* node = malloc(sizeof(struct Node));
node->k = 0;
node->link = 0;
return node;
}
void link(struct Node* from, struct Node* to)
{
from->link = &(to->link);
}
int main()
{
struct Node* child = create();
struct Node* parent = create();
link(parent, child);
return 0;
}
I've used void* for the link for the reason expressed by Dietrich: you want a pointer to the link to be the same type as the link. This effectively means a cast, so why not just use a generic pointer?
Membership in a structure, generalized or specific, is not an attribute of C data types. There is therefore no way to declare a pointer that can only point to a structure member, and not to any other variable of compatible type.
On the other hand, you don't need to do anything special to declare a pointer that can point to a member of another structure. You just need a pointer to that member's data type, and structure membership is irrelevant to that data type.
For example, you can have
struct node {
int k; /* number of links */
struct node **links; /* points to a dynamic array of node pointers */
struct node **one_link; /* points to a node pointer from another node */
};
In that case, it might make sense to do something like this:
struct node *n1 = /* ... */;
struct node *n2 = /* ... */;
n2->one_link = &(n1->links[3]);
Overall, though, I think this is kind of convoluted. There is probably a better way to structure your data.
Update:
Based on your description of what you're after:
[...] links are bidirectional, if I destroy one link (say the one that links node 1 to node 3) I'll need to destroy the node 1 link AND the corresponding link from node 3. Then I need to know more than just who is link to who. I need to know which link they are using.
there are at least two possible solutions, depending on details of how your nodes are structured. If they are structured like I show above, with an array (dynamic or not) of pointers to other nodes, then your general idea simply won't work. That's because the position of each link within an array of links will change as you delete other links (supposing that you close the gaps). Instead, you can just scan:
struct node {
int k; /* number of links */
struct node **links; /* points to a dynamic array of node pointers */
struct node *parent; /* points to a node that links to this one */
};
void delete_node(struct node *n) {
if (n->parent) {
int i;
for (i = 0; i < n->parent->k; i += 1) {
if (n->parent->links[i] == n) {
/* ... delete the ith element of n->parent->links ... */
break;
}
}
}
/* ... clean up node n ... */
}
If one node's links to others are stored in separate members, on the other hand, then you could indeed provide a double-pointer by which to remove links from the parent, but the presence of member k in your original structure tells me that's not your situation.
Ok, this is how I finally solved it in my program:
typedef struct node{
int k; //connectivity
struct link **enlace; //vector of LINKs
}NODE;
typedef struct link{
NODE *node1;
NODE *node2;
}LINK;
Basicly, I defined two structures: one is the NODE type, which contains the information of how connected is the node and a vector of LINKs, and the other is the structure LINK which contains the information of the link itself, I mean which nodes the link connects.
With these two I'm able to create the network of nodes with a connectivity following a Poisson distribution, and then destroy each link one by one, choosing one link at random from a list and then redirecting the pointers of each node to NULL.

Reusing existing linked list API implementation

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.

Using unions with structures

I have a structure like this:
struct data
{
char abc[10];
int cnt;
struct data *next, *prior;
};
struct data *start, *last;
struct data *start1, *last1;
struct data *start2, *last2;
The integer 'cnt' can have two values. The pointers:
struct data *start, *last;
are used to link all data with all values of 'cnt'. The pointers:
struct data *start1, *last1;
struct data *start2, *last2;
are used to link data when the value of 'cnt' is either 1 or 2. My problem is that when I change the value of 'abc' or 'cnt' for one linked list, say 'start->abc', the value 'start1->abc' and 'start2->abc' are unchanged because they live in different memory locations.
I would like a change in data under one list to be reflected in the other two lists. I believe 'unions' could help me do this but I don't know how to set it up.
Any help appreciated!
Nope, can't be done.
If even you come up with a solution that uses unions to get this done, you'll essentially have some data objects allocated in such a way that they overlap each other in memory. You'd end up with a contiguous memory block.
Rather than that, disregard the linked list altogether and use an array:
struct data {
char abc[10];
int data;
}
struct data datas[50];
struct data* some = datas[20];
struct data* prev = some - 1;
struct data* next = some + 1;
(Don't go out of bounds.)
If you really want a linked list for some reason, the whole point of them is that each element can be anywhere in the memory. This means that each element needs to remember the address of the next and the previous in order to allow two-way navigation.
Therefore, rather than thinking about union tricks, just make a function insertData or removeData that do basic operations on a list and also fixes all the pointers in neighbouring elements.
char global_abc[10];
int global_cnt;
struct data
{
char *abc;
int *cnt;
struct data *next, *prior;
};
start->abc = start1->abc = start2->abc = global_abc;
start->cnt = start1->cnt = start2->cnt = aglobal_cnt;
And now when you changed the
strcpy(start->abc, "any");
then it will be changed for the other elements.
And when you changed the
*(start->cnt) = 5;
then it will be changed for the other elements.
If you want the data to live on two lists simultaneously, the "all" list and the "cnt" list, then you need two sets of start, last pointers in the structure.
struct data
{
char abc[10];
int cnt;
struct data *next_all, *prior_all;
struct data *next_cnt, *prior_cnt;
};
When you change the value of cnt, you must remove the data from the next_cnt, prior_cnt list (corresponding to start1, last1 or start2, last2) and add it to the other.
Use a set of arrays to hold the data, and use a pointer to those arrays from your structures. Then "linked" entries can point to the same data buffer...
struct data
{
char* abc;
int cnt;
struct data *next, *prior;
};
struct data *start, *last;
struct data *start1, *last1;
struct data *start2, *last2;
char abcBuffer[2][10];
and in some function somewhere...
start->abc = abcBuffer[start->cnt];
start1->abc = abcBuffer[start1->cnt];
start2->abc = abcBuffer[start2->cnt];
In this case, changing the content of abcBuffer[n] will reflect the same change across all of the structures linked to that buffer. The key, however, is that you cannot do this using a "shared" structure such as a union, but have to manage it in your code.

Resources