C LinkedList add Ordered - c

I have a linked List c file/head as an independent library i am using for a project. I dont yet have a add ordered method in the library. My problem is writing a compare function because i want to compare on different items for different projects. How do i create a compare function in my main for whatever project i am using then pass and use that function into the add_ordered method in my linked list library? I cant seem to find a workable solution to passing in the function and using it within my linked list.
here is a uncompiled version of my add_ordered and compareto methods (compare to method will be different for each file):
void ll_add_ordered(ll_node *head, void *d){
ll_node *cur;
ll_node *temp;
if(head->size == 0){
ll_add_first(head, d);
}else{
temp = (ll_node *)malloc(sizeof(ll_node));
temp->data = d;
for(cur = head->next; cur->data != NULL && compareTo(temp->data, cur->data); cur = cur->next)
;
temp->next = cur;
temp->prev = cur->prev;
cur->prev->next = temp;
cur->prev = temp;
head->size++;
}
}
int compareTo(proc *first, proc *second){
if(first->arrival < second->arrival)
return -1;
else if(first->arrival > second->arrival)
return 1;
else
return 0;
}

One approach is to pass in a pointer to a function that takes void * arguments,e.g. int (*cmp) (void * lhs, void * rhs). In this case, it would be the responsibility of cmp to cast its arguments to the right type.
You might be able to do something a little more type safe with macros and token pasting but personally I find that to be overkill. If you are instantiating the linked list, then you know what the types are and can pass in a suitable comparison function.

This will define a type called compareFunc:
typedef int(*compareFunc)(void *first, void *second);
Now you would rewrite ll_add_ordered as:
void ll_add_ordered(ll_node *head, void *d, compareFunc compareTo) {
.
.
.
This will allow you to pass in any function that matches your compareTo function signature into ll_add_ordered and have it called when doing the comparison.

A simple solution would be to use a function pointer, and pass the pointer to the function.
I would recommend you declare an alias for the function signature as well, lest you get crazy after a while :)
I'm assuming ll_node.data is of type void *. Thus your linked list requires two things:
The comparison function takes two void pointers, compares them (using insider knowledge). The comparison function must know how to deal with the data. This requirement is of course implicitly enforced on the person/code/evil co-worker calling ll_add_ordered.
The comparison function returns 1, 0 or -1.
The type alias for such a function pointer would be:
typedef int (*ll_comp_func)(void *, void*);
If you think this looks crazy, you're totally right. It serves to make you crazyhomicidial late nights when nothing works. Anyhow, what it really does is create a typedef for a function pointer and it calls the alias ll_comp_func.
You would then alter your ll_add_ordered into the following form:
void ll_add_ordered(ll_node *head, void *d, ll_comp_func comparison){
// Do stuff.
int order = comparison(temp->data, cur->data);
// Do even more stuff.
}

Related

C Function pointer - not assigned but still works. Is there default behavior?

I have this code from a program given to me from a highly qualified instructor. Note the function pointer cmpfn below. It is used as a comparison operator. I did some reading up on function pointers and they make sense. However, nowhere in this codebase do I see it assigned to an actual defined function as I see in the tutorials I read online. It is never defined and assigned anywhere yet it appears to work. Is there some default behavior or how would you get this to work without assigning it as in cmpfn = &function_defined_elsewhere; ? Also why might he chose to use this function pointer as opposed to just a straight comparison operator?
/**
* Find an element in the list
*
* cmpfn should return 0 if the comparison to this node's data is equal.
*/
void *llist_find(struct llist *llist, void *data, int (*cmpfn)(void *, void *))
{
struct llist_node *n = llist->head;
if (n == NULL) {
return NULL;
}
while (n != NULL) {
if (cmpfn(data, n->data) == 0) {
break;
}
n = n->next;
}
if (n == NULL) {
return NULL;
}
return n->data;
}
Edit (Responding to feedback): Solved! What's below is for general public edification/curiosity but it makes sense to me now. Thanks for your indulgences.
I see now I needed to find where this function was being called. The above was in a file called llist.h and the pointer to the function (p2f) is called in a file called hashtable.c - twice actually. He actually uses p2f's a lot.
Here is one instance of a "p2f hosting" function being called:
/**
* Get from the hash table with a binary data key
*/
void *hashtable_get_bin(struct hashtable *ht, void *key, int key_size)
{
int index = ht->hashf(key, key_size, ht->size);
struct llist *llist = ht->bucket[index];
struct htent cmpent;
cmpent.key = key;
cmpent.key_size = key_size;
struct htent *n = llist_find(llist, &cmpent, htcmp); // HERE
if (n == NULL) { return NULL; }
return n->data;
}
So it's being passed htcmp. Previously I thought you had to assign a p2f to a function with the "=", but you can also do it through passing into calling function. I only learned about these today!
Here is htcmp's def:
/**
* Comparison function for hashtable entries
*/
int htcmp(void *a, void *b)
{
struct htent *entA = a, *entB = b;
int size_diff = entB->key_size - entA->key_size;
if (size_diff) {
return size_diff;
}
return memcmp(entA->key, entB->key, entA->key_size);
}
So it clearly returns an int, depending on difference between two htent (hashtable entry), noting either size difference or else calling powerful memcmp function.
This was a challenge to get to. The basics make sense but his code is very busy. I'll have to consolidate it in my sleep. There are so many structs and pointers to functions and much else interacting, but it was and is a great learning experience.
When you call the function llist_find you should pass the reference to the function, which must have the same prototype that is expected for llist_find.
And to answer your question, it's very helpful to use a pointer to function, especially when you are working with a structure where the comparison (this case) can be performed over one or multiple members of the structure. Also, as the function use void pointers, you can use the same llist_find to handle lists of different kind of structures.
You set the Pointer in This Parameter. So, when you call this Function I will automatically set these pointers automatically. So, I think you should look around the calling of this fuction. Then you will get the solution of your question
void *llist_find(struct llist *llist, void *data, int (*cmpfn)(void *, void *))

Using a function with a void pointer argument

I'm a C beginner experimenting with linked lists and I found a Github repo for one. the create function is written like this:
Node* ListCreate(void* data) {
Node *head = malloc(sizeof(Node));
if ( head != NULL) {
head->next = NULL;
head->data = data;
}
return head;
}
I was able to use it by changing the void* to int and then in main doing:
Node *root = ListCreate(5);
But then I read a little about void pointers and it seems like they can be used as generic types sort of like C++ templates, which would be useful if I could figure out how they work. I tried several things, and the closest I've got to getting it to work is no errors, but one warning:
incompatible integer to pointer conversion passing 'int' to parameter of type 'void *'
Am I missing a step here? I first felt like I should add something to the function definition, but I'm assuming the person who wrote it knows what they're doing and I just didn't use it properly in main. So is there a different way I'm supposed to pass an argument to this function?
As is mentioned by others in comment, it is more suitable to create different list for different types.
But if you want to use the same function definition, then use can pass the pointer to your data (int or char) and cast them as void *.
/* main: start */
int main(void)
{
Node *list_head; /* Points to first element in list */
Node *node_tmp; /* Just a temporary pointer */
int *pint;
char *pchar;
/* create an empty list */
list_head = NULL;
/* Note that there is no error checking done for
* malloc, which is not good
*/
/* Create a node which points to int */
pint = malloc(sizeof(int));
*pint = 10;
node_tmp = ListCreate((void *) pint);
/* Add this node to list */
list_head = add(node_tmp, list_head);
/* Create a node which points to char */
pchar = malloc(sizeof(char));
*pchar = 'c';
node_tmp = ListCreate((void *) pchar);
/* Add this node to list */
list_head = add(node_tmp, list_head);
/* print total number of nodes in list */
print_tot_nodes(list_head);
return 0;
}
Code for add and print_tot_nodes ommited are for brevity.
Note, that functions like print_tot_nodes or add will have not much issues if data points to different data types. But if you need to implement function like Node *smallest(Node *head), which returns pointer to the node having smallest element, then it may get complicated.
So, it is easier to use different list for different types. However you can cast the actual pointer to some datatype to void * if you need to use the same function definition as seen in your original post.
I think that there is a need to wrap for numeric literals(or cast?).
Like this:
void *BOX_VAR;//Not require if use GCC extension
#define BOX(type, value) ((*(type *)(BOX_VAR=malloc(sizeof(type))) = value), BOX_VAR)
#define UNBOX(type, value) (*(type *)(value))
Node *list = ListCreate(BOX(int, 5));
int v = UNBOX(int, list->data);
printf("%d\n", v);

If a parameter is a pointer type, is the parameter a pointer allocated in local memory

I'm just learning C, and I have a question about pointer parameters. My code is the following:
int Length(node *head)
{
int length = 0;
while (head) {
length++;
head = head->next;
}
return length;
}
The code in the book I'm reading says to do this though:
int Length(struct node* head)
{
struct node* current = head;
int count = 0;
while (current != NULL) {
count++;
current = current->next;
}
return count;
}
Is there really a difference? The way I'm reading my code is that I get a pointer to a node struct as a parameter. The pointer itself however, is a local variable that I am free to mutate as long as I don't dereference it first. Therefore, I can change the value of the pointer to point to a different node (the next node as it may be).
Will this cause a memory leak or is there some other difference I'm not seeing?
This code is for a linked list implementation. The node struct is defined as:
// Define our linked list node type
typedef struct node {
int data;
struct node *next;
} node;
Yes, they are both doing the same. But in the second example, it is more clear what the author is trying to do because of the code. In your first example, you're using the pointer head to reference nodes other than the head. That can be confusing.
You could write your function like this and your intend would be clear:
int GetLength(node* current)
{
int length = 0;
while (current != NULL)
{
length += 1;
current = current->next;
}
return length;
}
Your solution and reasoning is correct. The node argument is a local variable: a copy of the pointer passed to your function, allocated on the stack. That's why you can modify it from within the function.
There is no difference between the two solutions, at least not in functionality, modern compilers are most likely to optimize away the extra variable in the book's solution. The only slight difference is in style, many tend to take arguments as unmodifiable values just in case to avoid mistakes.
Your understanding of the argument-passing mechanics is correct. Some people simply prefer not to modify argument values, the reasoning being that modifying an argument tends to be bug-prone. There's a strong expectation that at any point in the function, if you want to get the value the caller passed as head, you can just write head. If you modify the argument and then don't pay attention, or if you're maintaining the code 6 months later, you might write head expecting the original value and get some other thing. This is true regardless of the type of the argument.

C - Can't initate a pointer that is passed as an argument

#include <stdio.h>
#include <stdlib.h>
typedef struct {
unsigned length;
} List;
void init(List *l) {
l = (List *) malloc(sizeof(List));
l->length = 3;
}
int main(void) {
List *list = NULL;
init(list);
if(list != NULL) {
printf("length final %d \n", list->length);
return 0;
}
return 1;
}
This is a simplified version of the code that is giving me problems. I am trying to construct the pointer *list from a method where *list is passed as an parameter.
I know I can make void init(List *l) work by changing it to void init(List **l) but this is for a class tutorial. I can't change the method arguments. I have spent four hours working on this.
I want to ensure that there is no way to make void init(List *l) work before I confront my professor.
Thanks in advance
You're passing a copy of the pointer to init, which is allocating memory, storing it in its local copy, and promptly leaking it when init returns. You cannot pass data back to the calling function this way. You need to either return the allocated data, or pass in a pointer to the pointer you want to modify, both of which involve modifying the function signature.
void init(List **l) {
*l = (List *) malloc(sizeof(List));
(*l)->length = 3;
}
init(&list);
Did the assignment specify that you have to allocate the List from within init? If not, you could always pass a pointer to an already allocated List object, and perform whatever initialization length = 3 is a place-holder for:
void init(List *l) {
l->length = 3;
}
List list;
init(&list);
printf("length final %d \n", list.length);
The problem is that the pointer is passed by value, so you're changes are discarded. You really need a pointer to a pointer to do this correctly. As in you would do:
void init(List** l) {
*l = (List*) malloc(sizeof(List));
// ...
}
And when you call it, you would use init(&list) instead of init(list). Of course, in this case, it makes sense to just go ahead and return the result instead of using a pointer to a pointer:
List* init() {
List* result = (List *) malloc(sizeof(List));
result->length = 3;
return result;
}
And then, with the above, you could simply use list = init();.
Note that in C++, you can use references instead of pointers, but mixing references and pointers is incredibly messy. Here, using a return-type is really the neatest thing to do.
If you absolutely have to use the existing signature, you can be sneaky and initialize the list, then in the init() function you can make the passed-in list's next pointer point to the list you actually want to create. Then, after init() has been called, you can take the next pointer and dispose of the original list object you created. Or you could always just have the first element by some dummy element.
this assignment is probably a good way to teach in a class the pass by value and pass by reference. If you want to maintain the constructor's signature you need to modify the main function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
unsigned length;
} List;
void init(List *l) {
l->length = 3;
}
int main(void) {
List list;// x = NULL;
memset(&list,0,sizeof(List));
init(&list);
printf("length final %d \n", list.length);
return 1;
}
Now here list is of type List and not address to List. the init() method passed the address of list and inside init you can change the value of the structure contents.
./a.out
length final 3
init needs to be passed a pointer to an existing List. I suspect that the real problem here is with your data structure. You have something called a List, that contains a length, but there's no list to be seen anywhere. List should probably contain a pointer to an array of the given length, and init should malloc that array and set the pointer. You will probably find this out when you ask the professor to correct his requirements which aren't broken -- if they were, he probably would have heard about it from past students and corrected them by now.

How to write a function within a function (list_map)

Hello I recently asked some questions on linked lists in C.
The link was found here
First I want to thank everyone for helping me with this. But I have one issue I cannot understand. I even asked the professor but he emailed me back with little information. Basically I am writing a linked list in C (see above link). One of the things the professor gives us in the header file is this:
void list_map( INTLIST *list, void (*f)(void *) );
/*Applies a function to each element of the list */
So I emailed him about this and said:
Another question, in the header file you did not define a sorting function, do we need to write a sorting function with the prototype and finally what is list_map
And he replied with:
You are asked to implement a sorting function f, which is called through list_map(list, f). Hope it clears your doubts.
My only doubts are this was not fully taught. I can understand how to sort the linked list in fact here is some pseudo code:
tmp=head;
while(tmp!=NULL)
{
tmp2=tmp->next; //pointer to next node
while(tmp2!=NULL)
{
if (tmp2->data < tmp->data)
{
int x = tmp2->data;
tmp2->data = tmp->data;
tmp2->data = x;
}
tmp2=tmp2->next;
}
tmp=tmp->next;
}
I know the experts might say this is not the most efficient, and I understand that right now I am just learning and trying to get things working. I can clean up afterwords...so on to my question.
My question is given I have the sort function (in the professor's case he calls it f). How would I call this sorting function when the signature is:
void list_map(INTLIST* list, void (*f) (void*));
Would I just say:
list_map(myList, f()); //apply function f to the current linked list
Or do I really need to define list_map somewhere? I am not the typical student just looking for someone to do my work. I am really trying to understand this as best I can.
Thanks to all of you.
[EDIT PORTION]
I wanted to add that one of the posters Kaleb P. said
"Thus, your job is to create a sorting
function that you will pass in to
list_map. Note that the correct syntax
for passing it in will be:"
So should my code simply be this:
in the .h file I prototype the function as:
void myCustomSort(void*);
And then in the .cpp it becomes:
void myCustomSort(void*f)
{
tmp=f->head;
while(tmp!=NULL)
{
tmp2=tmp->next; //pointer to next node
while(tmp2!=NULL)
{
if (tmp2->data < tmp->data)
{
int x = tmp2->data;
tmp2->data = tmp->data;
tmp2->data = x;
}
tmp2=tmp2->next;
}
tmp=tmp->next;
}
}
And to call it in main I would just do:
list_map(myListPointer, &myCustomSort);
But don't I need to define list_map anywhere? Because it is in the .h file do I not have to define it?
Assuming list_map is implemented like this, giving f each node in sequential order,
void list_map(INTLIST *list, void (*f)(void *)) {
INTLIST *node;
for (node = list; node; node = node->next)
f(node);
}
you can implement a selection sort
void list_sort(INTLIST *list) {
list_map(list, swap_head_with_smallest);
}
where void swap_head_with_smallest(void *) swaps the datum of a given node with the smallest of the data of any nodes following it in the list.
As this is homework, I'm trying not to give the whole solution away.
void swap_head_with_smallest(void *list) {
INTLIST *head = list;
INTLIST *smallest;
/* set smallest the smallest node of
head, head->tail, head->tail->tail, etc. */
/* swap head->datum and smallest->datum */
}
Your professor is trying to teach you a concept that's common in functional programming, which is the idea of a higher-order function. A higher-order function can take other functions as parameters, sort of like
list_of_cosines = map(cos, list_of_inputs)
where list of inputs is a series of floating point values, and cos is the normal cosine function. The map function will call cos for each value in list_of_inputs and return a list of the corresponding results.
C functions cannot take other function types as parameters, but they can take pointers to functions as parameters (usually termed a callback); the canonical example is the qsort() library function, which takes as one of its parameters a pointer to a function that accepts two pointers to void and returns -1, 0, or 1 depending on whether v1 < v2, v1 == v2, or v1 > v2, respectively. For example:
int compareIntValues(const void *v1, const void *v2)
{
int lv1 = *(int *) v1; // convert inputs from pointers to void
int lv2 = *(int *) v2; // to the type we're actually interested in
if (lv1 < lv2) return -1;
if (lv1 > lv2) return 1;
return 0;
}
int main(void)
{
int values[] = {3, 1, 4, 5, 7, 9, 6, 2};
...
qsort(values, // buffer containing items to sort
sizeof values / sizeof values[0], // number of items to sort
sizeof values[0], // size of each item
compareIntValues); // comparison function
...
}
qsort() will then call compareIntValues to order the elements in values. Similar to array expressions, a function designator will have its type implicitly converted from "function returning T" to "pointer to function returning T" depending on the context.
At this point I'm guessing, but it looks to me like your professor wants you to write the list_map function so that it will call a sorting function f with the list as the parameter, something like the following:
void list_map(INTLIST *list, void (*f)(void *))
{
// sort the list by passing it to f
f(list); // or (*f)(list);
}
void sortListAscending(void *ptr)
{
INTLIST *ilptr = ptr;
/**
* sort the list in ascending order
*/
}
void sortListDescending(void *ptr)
{
INTLIST *ilptr = ptr;
/**
* sort the list in descending order
*/
}
int main(void)
{
INTLIST *theList;
...
list_map(theList, sortListAscending); // sort the list in ascending order
...
list_map(theList, sortListDescending); // sort the list in descending order
...
}
The interface provided by your professor is a bit confused; either both the list pointer and the parameter to f() should be void * (in which case you could use list_map to map functions to different list types) or both the list pointer and parameter to f should be INTLIST * (since you seem to be dealing with INTLIST types).
If I'm right, then the exericise is a bit pointless on the surface (why not call the sorting function directly?), but it could be your professor is building up to something a bit more general-purpose. After all, there's no reason that f has to be a sorting function; it could be a function to display the list, or to save the list to a file, or something else.
I have a different example of how to use callbacks to sort a list here; it may help illustrate why this method is useful.
EDIT
ephemient's example of what list_map needs to do is probably much closer to what your professor intends than what I wrote.
The second parameter to list_map is a pointer to function returning void and taking in a void pointer. Since list_map appears to be a map function, I would guess that it will call f (the pointer to a function) for each element of the list.
Thus, your job is to create a sorting function that you will pass in to list_map. Note that the correct syntax for passing it in will be:
void yourCustomSort(void*);
list_map(myList, yourCustomSort);
I would guess that the void* being passed into your sorting function will probably be to a node within the linked list.
MergeSort is a good choice for sorting linked lists.
I believe that the list_map function calls the function pointer f() which is a pointer to a function that takes a void pointer and return void. If that is the case this is crazy way to implement a sort but doable.
Define a function like
void Test(void *)
{...}
And pass it in to the list_map() like so
list_map(listptr,Test);
I would assume your Test function gets called for each item in the list.
If in your node there is a pointer to the head of the list you have to use the pointer to the list as a frontier. Let me explain.
The map function is a common concept in functional programming, for now, you have just to know that is a function that get a list and apply another function (the applied function) to every node of the list was given to it. I bet you already knew it.
C language haven't, as far I remember, a map function, so you have to define one by your own it. It is not very difficult: Just start from the head of the list and walk to the tail. For every step pass the current listnode to the function that perform the operation you need to be performed (in this case the sort).
Now there is your assignment.
You cant get any data from the applied function (it returns void)
You have to walk down until the end of the list passing every single node to the function that do the sorting.
It is useless to sort the list you haven't already visited, as you would keep to sort it for every node (sorting an already sorted set it is not too smart to me) ;)
Your applied function get a single pointer. This in clearly stating that that pointer (the node you are at) represent a line: on his left (to the head) there is the part of list already sorted, to the right (to the tail) there are the wild elements.
Since Your applied function get as input just a simple void * , I think it is better to leave the pointers alone and exchange the payload of the nodes
Said that, the pseudocode for your sorting function, one of the possibile ones, can be:
void ascendingSort(void*f)
{
cursor=f->head;
placed=false;
while(!placed and cursor!=f) {
if (cursor->data < f->data) {
cursor = cursor->next;
} else {
swap( cursor->data, f->data);
placed=true;
}
}
while(cursor!=f) {
cursor = cursor->next;
swap(cursor->data, f->data);
}
}
Or, in a more concise form:
void ascendingSort(void*f)
{
cursor=f->head;
while(cursor!=f) {
if (cursor->data > f->data) {
swap( cursor->data, f->data);
}
cursor = cursor->next;
}
}

Resources