How would you link a linked list with different struct - c

I have 2 different stuct
typedef struct name {
char*markerName;
struct test *next;
}name_t;
typedef struct test {
int grade;
int studentNumber;
struct test *next;
}test_t;
and this function
void test(name_t* marker1,int data)
{
test_t *temp= malloc(sizeof(test_t));
test_t *location=NULL;
temp->grade=data;
temp->next=NULL;
location=marker1->next;
if(location==NULL)
{
// printf("%i \n",temp->grade);
marker1->next=temp;
}
else
{
while(location!=NULL)
{
printf("%i \n",location->grade);
printf("%p \n",location->next);
location=location->next;
}
location=temp;
}
}
the problem is we are creating an array of the stuct name and creating a linked list of the test after EACH ELEMENT OF THE ARRAY. How would I link the node of the struct name into the stuct test?
I printed the next out and they keep pointing to NULL pointer.

Strictly speaking, a linked list can only contain one data type. If you want to have a list containing both structure types, you can emulate this using a union:
struct name {
char* markerName;
};
struct test {
int grade;
int studentNumber;
};
// Indicates the type of data stored in the union
enum dtype { NONE, NAME, TEST };
// Combination of the above structures, suitable for a mixed-type list
struct combo {
struct combo* next; // Next structure in the linked list
enum dtype type; // Indicates which of the union fields is valid
union {
struct name name;
struct test test;
};
};
This stores both sets of data in a single structure, allows you to make lists from the structures, and enables you to keep track of which type of data is currently valid.

You are overshooting past the end of your linked list. You end up with 'NULL' for your location variable, which, even if it could be assigned, is still a local variable that goes out of context when your function exits. Your while loop should look more like this:
while(location->next != NULL)
{
printf("%i \n",location->grade);
printf("%p \n",location->next);
location = location->next;
}
location->next = temp;

What about a struct with two types of next pointers: one of type name_t and other of type test_t. You can use the one you want for linking and leave the other one NULL. I hope I understood your question correctly.

You could use a pointer to type void. This, of course, assumes that you know the type of the next object somehow.
When you want to create a heterogeneous data structure, it might be smarter to have only one struct type of nodes, and have two "payload" variables in the nodes, one which tells you the type of the node, and a pointer to a structure with the actual data.

Related

How do you use void pointers to create a more general node structure?

I'm making an RPN Calculator that uses stacks and queues implemented as a linked list structure. The problem is that the structure needs to be able to handle both symbols and numbers (including a data type I created for mixed numbers). For this my teacher recommended using a void pointer type to store the data for each node as shown here:
typedef struct node {
void* data;
struct node* next;
} Node;
I'm not sure how to
dereference the pointer to use its address value or
add a node with different data types (int, char, or mixedNum)
For this my teacher recommended using a void pointer type to store the data for each node
Don't use void* unless you really need to, it's a bare untyped pointer to an arbitrary block of memory, and there are many pitfalls and potential bugs working that way.
the structure needs to be able to handle both symbols and numbers (including a data type I created for mixed numbers).
That sounds like a job for a union, where you have another member tagging the type. Try something like this:
/* A tag to for the union type */
typedef enum
{
Number,
Symbol
} NodeType;
/* A Node can contain a symbol or numeric value */
typedef union
{
char* symbol;
float number;
} NodeData;
/* A linked list */
typedef struct Node
{
NodeType type;
NodeData data;
struct Node* next;
} Node;
I suggest you create functions to do things like create a new symbol node, create a numeric node, setting the tag accordingly. You will probably want to strdup the symbol name so you own a copy of the string. A function to free a node (including freeing the string if it is of that type), etc, etc.
As others, have already mentioned, a union is a better choice for this situation where you only need a few data types.
Although this is true, void* is more versatile and is a must if you want to create a more "general" linked list that can handle even custom types without you declaring it explicitly.
So, first of all, when implementing it with void*, it is quite common to use some typedefs that makes the code more readable. These are:
typedef void* Pointer
typedef struct node* ListNode
typedef ListNode* List
This will allow you to create a list simply by:
List list;
So, to answer to the question:
1) Let's assume you have a ListNode with an int* inside. To dereference it, you have to (int*)(ListNode->data). That casts Pointer to int*. If you want to get the actual value, you can always add an asterist before it.
2) The insert function would look something like this:
void insert(List list, Pointer data);
Since the data you give it is of type Pointer, you can put whatever you want there. For instance, if you want to put an int, you could do so by:
int a = 5;
insert(my_list, &a);

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);
}
}

Creating a map without using a struct as linked list

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.

Polymorphic data structures in C

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);

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