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;
}
}
Related
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 *))
In my project I have linked links of struct elem and each elem has many different attributes.
Currently each time I want to get an elems attribute, I call a function such as:
get_elem_address(&linked_list);
get_elem_this(&linked_list);
get_elem_that(&linked_list);
In each function I have the same bit of code:
struct elem *elem = linked_list->first_elem;
while (elem != NULL) {
if (elem->identifer == identifer) get_elem_whatever_i_need;
elem = elm->next;
}
In some functions I can guarenteee that there will be an element where the identifers match, in other functions I am not sure. Is there a way I can write a function that will go through the linked list and find the element I want and then return it.
The reason why I am not sure if i can do this is because of the cases where it may not an elem that has the same identifer as the passed in one.
This answer is probably going to get a lot of comments from the traditional C programming community, not unlikely to get a lot of down votes either, but I'm still going to give it.
You could consider using a functional programming approach. For a simple linked list it is arguably overkill and I personal (too) would just stick with the loop you gave, but on more complex data-structures it is definitely worth considering. The linked list does make for a good demonstration.
So let's assume we have the following linked list:
#include <string.h>
typedef struct elem
{
struct elem * next;
char * identifier;
} t_elem;
then we could program a generic finder function as follows:
t_elem * find(t_elem * list, int (*sel)(t_elem * elem))
{
for (; list != NULL; list = list->next)
if (sel(list))
{
break;
}
return list;
}
It takes a selection function as a parameter, in C programming often called a call back and returns the first element in the list for which this function returns non-zero. Finding the first element with a certain identifier could then look as follows:
t_elem * find_id(t_elem * list, char * id)
{
int sel(t_elem * e)
{
return strcmp(e->identifier, id) == 0;
}
return find(list, sel);
}
The above function is non-standard ANSI as it is using a nested function. GCC supports this and I would encourage the standardization committee to adopt such nested functions for this very reason.
If you want or have to stick to standard ANSI then you will have to make the so called closure explicit as I've done in the following example. In this case the closure simply consists of the parameter id, but in general a dedicated struct must be defined. The closure is passed around as void pointer and cast to the appropriate type whenever used (error prone indeed).
t_elem * find2(t_elem * list, int (*sel)(t_elem * elem, void *), void * cl)
{
for (; list != NULL; list = list->next)
if (sel(list, cl))
{
break;
}
return list;
}
int sel_id(t_elem * e, void * cl)
{
char * id = cl;
return strcmp(e->identifier, id) == 0;
}
t_elem * find_id2(t_elem * list, char * id)
{
return find2(list, sel_id, id);
}
If you feel comfortable with such an approach is of course up to you, but for me it has become a standard tool.
i try this:
void
remove_duplicate(List l, int p, int r){
if(p<r){
int q =(r+p)/2;
remove_duplicate(l,p,q);
remove_duplicate(l,q+1,r);
merge_(l,p,q,r);
}
}
void
merge_(List lst, int p, int q, int r){
int i = p;
int j=q+1;
int l = r;
link lp = retNode(lst,p);
link lq = retNode(lst,q+1);
while(i<=q){
j=q+1;
while(j<=l){
if(lp->item==lq->item){remNode(lst,j);j--;l--;}
j++;lq=lq->next;}
i++;lp = lp->next;}
}
But the size of "sub-list" get lower when I remove an element and then doesn't work, any ideas?
This recursive approach isn't going to work very well, because as you've spotted when you remove items from the array you'll have to move everything down. This will mess up the offsets in the list for the parent recursive call.
You could modify the call to merge so that the arguments are pointers and they get updated to the new values if the list is resized. Then you'd also have to have remove_duplicates also return these values in the same way. This is likely to be quite fiddly, but if you're changing the size of the list then I don't see any other approach - parent calls in the recursion chain need to know that their bounds have changed by the inner calls deleting items from the list. Just remember to take a copy of the values passed in by pointer before passing them into the next call down, or you'll just have pointers to the same variables all the way down and that will break things horribly.
However, do you really need to use a recursive approach? I don't think it's either the easiest or most efficient approach - in this case, an iterative method is likely to be far easier to implement.
You seem to be using linked lists, so an iterative approach might look like this:
void remove_duplicates(ListItem *items)
{
while (items) {
ListItem *current = items;
while (current->next) {
if (current->next->item == items->item) {
current->next = current->next->next;
} else {
current = current->next;
}
}
items = items->next;
}
}
I've assumed your lists are terminated by a NULL next pointer in this example, but it should be easy to adapt for length-bounded lists as well. I've also assumed it's only singly-linked - the basic approach for doubly-linked lists would be similar but of course you need to update both next and previous pointers.
#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.
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.
}