Creating and using generic methods in C - c

I wrote a Linked List ADT for a class I am in originally for a list of ints. Now I am going to use the same list for chars and ints. I know how to rewrite the code for chars to just have basically two List ADTs, one for the ints and the other for the chars.
I don't want to do that however, I want to write it for a generic variable so that in the future I can use this ADT with other code without worrying about types to much.
Initially I went into this with void*, but I am running into an error with it that I am just have a hard time understanding how to fix.
typedef struct NodePtr {
void* data;
struct NodePtr*next;
struct NodePtr*prev;
} NodePtr;
typedef struct ListStruct {
NodePtr* first;
NodePtr* last;
NodePtr* current;
} ListStruct;
Then some other code and fun stuff, and then my insert method to insert at the front of the list:
void insert(listhndl L, void* data)
{
...inserting of the node here.
}
This code throws no error, but then when I run a driver to test it:
ListHndl test = NULL;
test = newList();
insert(test, 1);
I get the error message:
warning: passing argument 2 of 'insert' makes pointer from integer without a cast [enabled by default]
insert(test, 1);
^
error: expected 'void *' but argument is of type 'int'
void insert(ListHndl L, void* data);
I am confused here because how can it throw an error saying it's not the type it expected, if void* is a generic type?
What am I doing wrong?
I saw on here some people recommend using enum and unions for generics instead of void*, but I could not get that to work ether as I don't really understand what to do with them. If somebody wanted to also answer how to do generics with the enums/unions method I would greatly appreciate it.

Your list addition parameter is a void* so naturally you'll be flagged with an implicit conversion warning (or error if you're compiling with -Wall -Werror like you should be). Generic implementations of any node management algorithms isn' a trivial as it may seem, and much has been written/coded on the subject.
In your case, you could dynamically allocate the data being added yourself (i.e. allocate an int and send the resulting address as the void*, or create additional parameterization of your list interface functions and make them smart enough to figure out what to allocate (if anything)
In general, a generic linked list is eventually not going to escape ownership and sizing information if you're planning on using pointers (and all of the samples linked below go to some lengths to accommodate this). An elaborate enough interface capable of constituting this information into a reasonable node architecture that is generic enough is tedious, but that is the price you pay for generics. Performance is likewise a factor, and again, pay the piper. Type information for a list that holds different data types may also be a consideration, in particular if you're inclined in your algorithms to minimize memory management usage.
There are a multitude of generic linked lists sourced all over this grand illusion we call the World Wide Web. Here are a few such implementations:
PseudoMuto Generic Linked List : Assumes all items are the same size, maintains dynamic storage to them via internal memory management.
CMU Generic Linked List: lecture notes on generics development.
Uncredited Generic List (circa 1999): Another fixed size dynamically managed linked list. Not particularly impressive, but at least functional.
Atachil's Generic Linked List: Yet another generic implementation, this one implemented as a double-linked list.
Plenty more where that came from (google and 10 minutes of filtering out junk).
You needn't reinvent the wheel, but if you want to there are plenty of examples out there that can assist you. A challenge would be implementing a list that
Takes user-provided allocation/deallocation functions for any memory management requirements
Uses a union internal to the list_node that supports all the fundamental data types as well as a void* and size_t for blob or string data, and of course, a type-identifier so you know what member is the member.
Provides dynamic ownership semantics (i.e. allows the client to specify a dynamic node pointer is "owned" by the client and to not store a duplicate; just use the provided data pointer.
Bi-directional management (i.e. a double linked list)
Just a few things to consider when embarking on your quest. I wish you the best of luck.

You can make the type of data to be handled more opaque by encapsulating it into a typedef:
typedef struct my_opaque_data {
int item; /* example opaque data */
} DATA;
struct NodePtr {
DATA data;
struct NodePtr *next, *prev;
} NodePtr;
So far, all I have done is replace void * with DATA.
Then you will probably want to declare some basic operations to be implemented elsewhere to handle the type:
extern int data_compare (const DATA *left, const DATA *right); /* return < 0 if left < 0, 0 if equal, etc. */
extern void data_set (DATA *dest, const DATA *src); /* *dest = *src */
extern void data_swap (DATA *d1, DATA *d2); /* exchange *d1 and *d2 */
extern size_t data_size (const DATA *d); /* return size (bytes) of *d */
...
Each of these is almost certainly trivial to implement, but by substituting different data types, even complex data types, in DATA, the source code can remain complete generic and oblivious to what is in DATA. With this one could easily implement list operations, sorting, searching, etc., etc.

Related

How to store custom objects (struct) in C?

I want to know how to store custom objects (not their pointers) in C. I have created a custom structure called Node
#define MAXQ 100
typedef struct {
int state[MAXQ];
int height;
} Node;
(which works) and I want to store a few of these Nodes in a container (without using pointers, since they are not stored elsewhere) so I can access them later.
The internet seems to suggest something like calloc() so my last attempt was to make a container Neighbors following this example, with numNeighbors being just an integer:
Node Neighbors = (Node*)calloc(numNeighbors, sizeof(Node));
At compilation, I got an error from this line saying
initializing 'Node' with an expression of incompatible type 'void *'
and in places where I referenced to this container (as in Neighbors[i]) I got errors of
subscripted value is not an array, pointer, or vector
Since I'm spoiled by Python, I have no idea if I've got my syntax all wrong (it should tell you something that I'm still not there after scouring a ton of tutorials, docs, and stackoverflows on malloc(), calloc() and the like), or if I am on a completely wrong approach to storing custom objects (searching "store custom objects in C" on the internet gives irrelevant results dealing with iOS and C# so I would really appreciate some help).
EDIT: Thanks for the tips everyone, it finally compiled without errors!
You can create a regular array using your custom struct:
Node Neighbors[10];
You can then reference them like any other array, for example:
Neighbors[3].height = 10;
If your C implementation supports C.1999 style VLA, simply define your array.
Node Neighbors[numNeighbors];
(Note that VLA has no error reporting mechanism. A failed allocation results in undefined behavior, which probably expresses itself as a crash.)
Otherwise, you will need dynamic allocation. calloc is suitable, but it returns a pointer representing the contiguous allocation.
Node *Neighbors = calloc(numNeighbors, sizeof(*Neighbors));
Note, do not cast the result of malloc/calloc/realloc when programming in C. It is not required, and in the worst case, can mask a fatal error.
I want to store a few of these Nodes in a container (without using pointers, since they are not stored elsewhere) so I can access them later.
If you know the amount of them at compile-time (or at the very least a reasonable maximum); then you can create an array of stack-allocated objects. For instance, say you are OK with a maximum of 10 objects:
#define MAX_NODES 10
Node nodes[MAX_NODES];
int number_nodes = 0;
Then when you add an object, you keep in sync number_nodes (so that you know where to put the next one). Technically, you will always have 10, but you only use the ones you want/need. Removing objects is similar, although more involved if you want to take out some in the middle.
However, if you don't know how many you will have (nor a maximum); or even if you know but they are way too many to fit in the stack; then you are forced to use the heap (typically with malloc() and free()):
int number_nodes; // unknown until runtime or too big
Node * nodes = malloc(sizeof(Node) * number_nodes);
...
free(nodes);
In any case, you will be using pointers in the dynamically allocated memory case, and most probably in the stack case as well.
Python is hiding and doing all this dance for you behind the scenes -- which is quite useful and time saving as you have probably already realized, as long as you do not need precise control over it (read: performance).
malloc and calloc are for dynamic allocation, and they need pointer variables. I don't see any reason for you to use dynamic allocation. Just define a regular array until you have a reason not to.
#define MAXQ 100
#define NUM_NEIGHBORS 50
typedef struct {
int state[MAXQ];
int height;
} Node;
int main(void)
{
Node Neighbors[NUM_NEIGHBORS];
Neighbors[0].state[0] = 0;
Neighbors[0].height = 1;
}
Here NUM_NEIGHBORS needs to be a constant. (Hence static) If you want it to be variable or dynamic, then you need dynamic allocations, and pointers inevitably:
#define MAXQ 100
typedef struct {
int state[MAXQ];
int height;
} Node;
int main(void)
{
int numNeighbors = 50;
Node *Neighbors;
Neighbors = (Node*)calloc(numNeighbors, sizeof(Node));
Neighbors[0].state[0] = 0;
Neighbors[0].height = 1;
}

Printing elements of a linked list containing void*

I'm implementing a generic doubly linked list in C, and I've written functions for forward and backward traversal. Within these functions, I'd like to print the data contained in the list, but since it's generic, I'm having a hard time figuring out how this can be done. Obviously I can't just printf using %d or something because the list could contain any data type. Any suggestions to approach this differently would be appreciated because I've been thinking about it for quite some time and I'm at a loss. Thanks!
You can do a lot of things.
For example, you can store structs that not only contain a void * to your element's data, but also an indication for the possible data type, or even just the format string necessary to printf the object.
You could also think of a struct that contains a void * to your data, and a function pointer that will allow you to convert your data to a string. That is basically minimally emulating C++'s polymorphism in C.
EDIT: as wickstopher pointed out, you just don't get compile-time type safety with this. Mess up the function pointer, and you'll have an unsuitable function working on your data, possibly causing your program to segfault, run over your kitten, burn down your apartment, run away with your youngest child or smoke crack in your kitchen.
You need a tag field in the struct you declared for node. Define an enum for data types as
enum {INT_TYPE, FLOAT_TYPE, DOUBLE_TYPE, CHAR_TYPE} type;
For every data type you need to assign type with corresponding enumeration constant. In printing function you will have to check the value of type and then use the appropriate specifier.
C does not support any sort of runtime type checking, so this is not possible. See runtime determine type for C (similar question).
If you want to support a limited range of data types, you might consider an adding an enum to your node structure, but this won't get you true generic functionality and won't be enforceable at compile time.
Assuming your node has a void * pointer to node contents, among pointers for referring the next and previous elements in the list, provide a function to print a node, such as
void PrintNode (Node_t *node, void (*fprint)(void *));
This function will get the elements of a node, and then call a user-provided function to actually print the contents of a node.
typedef struct stNode {
void *NodeContents;
struct stNode *prev;
struct stNode *next;
} Node_t;
void PrintNode (Node_t *node, void (*print)(void *))
{
if (node && node->NodeContents && print)
print(node->NodeContents);
}

Simulating array_pop for various structures in C

I am new to C but I am currently working on a project which I cannot work out how I can do what is needed.
I have 2 different struct arrays, they are completely differently defined and I am trying to do the same action as PHP's array_pop would do, i.e. remove the last element of the array structure.
I know I could create 2 separate functions, one for each structure type, but obviously is not the best idea, so am wondering whether it is possible that I can pass either structure type to the one function, and possibly a flag, and the flag determine what type of structure it should be cast to.
My structures are defined as follows
typedef struct CallLogSearchResultStruct
{
long date;
int dRowIndex;
} callLogSearchResultStruct;
typedef struct CallLogSearchDataStruct
{
char * date;
char * time;
char * bParty;
char * aParty;
float duration;
char * cleardownCause;
struct CallLogSearchOutboundStruct * outboundLegs;
} callLogSearchDataStruct;
Below is how the structures are initialised
callLogSearchData = calloc(numRows, sizeof(callLogSearchDataStruct));
callLogSearch = calloc(numRows, sizeof(callLogSearchResultStruct));
numRows being the number of structs to contain within the array.
Below is how I am using the structures
callLogSearchData[dataRow].aParty = NULL;
callLogSearchData[dataRow].bParty = NULL;
callLogSearchData[dataRow].cleardownCause = NULL;
callLogSearchData[dataRow].date = NULL;
callLogSearchData[dataRow].time = NULL;
callLogSearchData[dataRow].outboundLegs = NULL;
Apologise if this is a simple straight forward answer, I can't find anything on Google, although not entirely sure what this would be called so maybe I'm using the wrong keywords.
Thanks for any help you can provide.
What do you mean by "remove"? How are the arrays allocated?
If you have an array created by a declaration such as:
struct foo my_foos[123];
there is nothing you can do to change the fact that my_foos is 123 elements long. You can of course select to ignore some of them by having a separate size_t foo_count variable that you maintain.
Arrays in C are not generally dynamic (unlike lists/arrays in many more high-level languages). You can implement a dynamic array using malloc(), which is not too hard but it's unclear if that's what you've done.
If you're open for using external files, have a look at utarray:
It's a collection of macros stored in one header that allow what you're searching for. No need to link an additional library, just #include the file and you have what you need.
You'd have to implement a custom UT_icd providing functions to init, copy and free the elements stored in the array.
What you want is actually a linked list. It is a collection of structures each one pointing to the Nth element and to the next element in the list. That way you can easily remove any element by unlinking it in the chain. You can google for a linked list lib in C or, implement one (it's a good exercise).
Arrays in C are static memory ranges with only enough space for your elements. Nothing more. In general you can not remove one element. You can, however, use realloc function to resize an existing array.
For what you're trying to do I'd go for a linked list.

Memory management while implementing a generic linked list library in C

I'm implementing a generic Linked List in C
struct Node
{
void* data;
struct Node* next;
};
Is it better to let the user worry about allocating and deallocating what data will point to, or should we do it ourselves? If left to the user they may store stack objects into the list which could cause problems later. I just wanted to know which design is better.
The general rule of thumb is usually: Who allocates a memory - is responsible for freeing it.
In your case, you should take care for the nodes themselves, and the user should be responsible for the data.
It makes sense because:
By taking responsibility on the nodes- it gives you more freedom to change implementation in future versions, without needing to worry about backward compability.
You cannot know how and if to free data - it could be a complex type that needs freeing in inner fields as well, or it could be pointing to a stack allocated space, which will cause an error if trying to free it.
In addition, remember that if a user took an element out of the
list - it does not mean he wants to destroy the data. Maybe the
list is a queue, and the element is currently being processed by
him?
You can also create a function that takes a function pointer and data type to deallocate in your generic link list. User can supply customized code in the function and pass pointer to that function to execute their version of code to free the allocated memory in the complex data type, e.g. nested structures that need to be traversed or a structure that has multiple pointer variables that need to be deallocated as well.
Following is a snippet for this idea.
main.c
int int_data; /* int can be replaced by any other data type */
deallocate_data(user_defined_free, &int_data);
void user_defined_free(void *data)
{
int *i = (int *)data;
/* cast to your data type and
perform deallocation */
}
somewhere in your generic linked list code
void deallocate_data (void (*p)(void *), void *data)
{
/* call user defined function to free their data structure */
p(data);
}

Casting a 'BigStruct' to a 'SmallStruct' in C (similar structs with static arrays of different sizes)

Supposed that for some reason you are only allowed to use static memory in a C program.
I have a basic structure that I am using in several places defined as below:
#define SMALL_STUFF_MAX_SIZE 64
typedef struct {
/* Various fields would go here */
...
double data[SMALL_STUFF_MAX_SIZE]; /* array to hold some data */
} SmallStuff;
Now, I have been asked to add a new feature that lead to a particular case where I need the same structure but with a much larger array. I can't afford to max up the array of the SmallStuff structure as memory is too tight. So I made a special version of the struct defined as below that I eventually cast to a (SmallStuff*) when calling functions that expect a pointer to a SmallStuff structure (the actual size of 'data' is properly handled in these functions)
#define BIG_STUFF_MAX_SIZE 1000000
typedef struct {
/* Various fields, identical to the ones in SmallStuff would go here */
...
double data[BIG_STUFF_MAX_SIZE]; /* array to hold some data */
} BigStuff;
Obviously, the proper way to do it would be to dynamically allocate the memory but as said above I can't use dynamic memory allocation.
Are there any side-effects that I should consider?
Or better ways to deal with this kind of problem?
Thanks in advance.
What you're doing is fine, though it tends to scare people who are uncomfortable with pointers and casting.
The general solution for your problem is to get rid of BigStuff and SmallStuff and make a single Stuff structure with a size member and a double *data that points to an array of your choosing, instead of risking potential miscasts in your code later or having to change your functions when you discover you also need MediumStuff. This gives you the flexibility of using whatever sizes are appropriate.
typedef struct
{
// the usual
size_t data_length;
double *data;
} Stuff;
double bigdata[BIG_STUFF_MAX_SIZE];
Stuff big = { ..., BIG_STUFF_MAX_SIZE, bigdata };
typedef struct {
/* Various fields would go here */
double data[]; /* a flexible array (C99 extension) */
} AnySizeStuff;
typedef struct {
AnySizeStuff header;
double smalldata[SMALL_STUFF_MAX_SIZE];
} SmallStuff;
typedef struct {
AnySizeStuff header;
double bigdata[BIG_STUFF_MAX_SIZE];
} BigStuff;
Then if x is either a SmallStuff or BigStuff, you can pass &x.header to routines that can take either.
Although its ugly code because of the complexity, there should not be any runtime problems because the sizes are hard-coded.
A better way to deal with it is to have algorithms which didnt need you to have 2 separate structs which only differ by size. However, I dont know your application, so you know best how to deal with this problem.

Resources