1

My professor defined this in the .h file

void list_map(INTLIST* list, void (*f)(void *)); /*Applies a function to each element of the list */

I wrote the function like this:

 void list_map(INTLIST* list, void (*f)(void *))
  {
   INTLIST* pTemp=NULL;

   if (list == NULL)
    {
      //list is empty
    }
   else
      {
       for(pTemp=list; pTemp->next!=NULL; pTemp=pTemp->next)
          {
             f(pTemp); //f is a function pointer we call list map from main like list_map(lst, list_sort)
          }    
      }
  }

I call it in main like this:

  list_map(aList[i], (void*)list_sort);

In windows environment, no complaints, but I have to run this in a Linux environment. I'm using a makefile to compile all of the code and I get this warning and error:

*c++ -O2 -c main.c main.c: In function ‘int main(int, char**)’: main.c:53: warning: deprecated conversion from string constant to ‘char*’ main.c:123: error: invalid conversion from ‘void ()(INTLIST)’ to ‘void ()(void)’ main.c:123: error: initializing argument 2 of ‘void list_map(INTLIST*, void ()(void))’ make: *** [main.o] Error 1*

Can somebody help with the error first and then maybe with the warning?

Edit Portion:

Someone asked for the list_sort function, here it is:

 void list_sort(INTLIST* list)
 {
  INTLIST* pTemp=NULL;
  INTLIST* pTemp2=NULL;

  pTemp=list;          //temp pointers to compare node values
  pTemp2=list;

  if (pTemp->next !=NULL)     //move to second node
   {
      pTemp2=pTemp2->next;
   }

  while(pTemp2 != NULL)
   {   
       //we implement a selection sort 
       //check if incoming node->datum with each node in the list
       //swap values if <
      if (pTemp2->datum < pTemp->datum)
         {
         //swap the values
         int temp = pTemp->datum;
         pTemp->datum = pTemp2->datum;
         pTemp2->datum = temp;
         }
         //advance the pointer
      pTemp2=pTemp2->next;
   }
 }
2
  • What does list_sort look like? Commented Jan 25, 2010 at 2:30
  • Can you change the list_sort function, or is that also fixed by the prof? If it is fixed, seems like you have been dealt a tough hand. Commented Jan 25, 2010 at 4:19

5 Answers 5

2

And if you cast your callback to the proper function type?

list_map(aList[i], (void (*)(void*))list_sort);
Sign up to request clarification or add additional context in comments.

3 Comments

"If what you get is not a duck, punch it until you get what you want" - I am sorry but this is a bad answer to give to a beginner...
@LiraNuna: It's a homework and he can't change the prototype of list_map. I'm afraid his teacher wants him to punch it until it quacks like a duck.
this will make the warning go away, but now it'll invoke undefined behaviour when the function gets called within list_map()
2

Well,

void list_sort(INTLIST* list)

has the wrong signature to be passed as the second argument of

void list_map(INTLIST* list, void (*f)(void *))

1 Comment

Been trying to follow this stuff as I too am learning C...but I guess my question is it looks like list_map's void (f) )(void) is that just a function pointer? What could he change void list_sort to become? void list_sort(void* list) ?
2

A simple cast of list_sort() is enough to make the warning go away, but it's not enough to make it actually work:

The C-standard doesn't guarantee that an INTLIST * and a void * have compatible representations, ie void (INTLIST *) and void (void *) are distinct, incompatible types. When list_map() invokes list_sort() through your void (*f)(void *) argument, C99 section 6.3.2.3, §8 applies:

If a converted pointer is used to call a function whose type is not compatible with the pointed-to type, the behavior is undefined.

To make it standard compliant, you have to write a wrapper function for list_sort():

void list_sort_wrapper(void *list)
{
    list_sort(list);
}

and use that as argument to your call:

list_map(aList[i], list_sort_wrapper);

Also, if list_sort() is implemented correctly (didn't check the algorithm), it already walks the list, ie invoking it for each node doesn't make any sense at all.

edit:

Ok, list_sort() doesn't actually sort the whole list - that can be achieved via

list_map(list, list_sort_wrapper);

The naming scheme is a serious WTF - if the function doesn't sort the list, call it list_sort_step() or list_select_head() or something, but please not list_sort().

1 Comment

list_map was a mapping function that takes a function pointer to list_sort() so as long as you call list_map you end up sorting the entire list, even though list_sort is doing this element by element. I know it looks strange, but professors are strange people who really can't code.
1

First: why are you compiling C code as C++?. Please compile it with a C compiler.

The prototype of list_sort() is:

void list_sort(INTLIST* list);

and list_map() has the prototype:

void list_map(INTLIST* list, void (*f)(void *));

This means that the second argument to list_map() is a function that takes a void * argument, and returns void (nothing).

Now, the C standard guarantees that a conversion of any object pointer to void * and back is OK, so given:

INTLIST *l;
/* make l point to a valid INTLIST */
void *pl = l;

this is OK:

list_sort(pl);

Note that, list_sort() could have been declared as:

void list_sort_generic(void *l);

In fact, since your professor is using void * in some places, he wants to extend your lists to be of a generic type at some point.

Anyway, you can pass an INTLIST * to list_sort() or list_sort_generic(), but list_sort_generic() can be passed any object pointer, whereas list_sort() can only be passed INTLIST * (or a void * which was converted from an INTLIST *).

Even though list_sort() can take a void *, the signature of list_sort() is not:

void list_sort(void *l);

So, the function types of list_sort() and list_sort_generic() are not the same, and cannot be interchanged. list_map() expects a function of the kind that list_sort_generic() is, but is getting a function of a different kind.

Since you can't change any prototypes, you need a cast. Now, void * is a generic type in C, so you would think such a cast would work. But, as I said before, only object pointers can be converted to void * and back portably—not function pointer type. So, you need to cast list_sort() to the correct type when calling list_map().

That correct type is void (*)(void *). This is a function returning void and taking a void *.

Hence, the call should be:

list_map(aList[i], (void (*)(void *))list_sort);

But, since the type of list_sort() and the type expected by list_map() for its second parameter are not the same, the cast may or may not work. Your professor has given you "not-so-nice" (i.e., wrong) prototypes. Either he should have gone all the way in declaring type-generic functions, or he should have kept everything INTLIST *. By going half-way, he has introduced a complicated cast that shouldn't have been there, and may not work. I am sure if you bring this to your professor's attention, he will admit this oversight.

Hope that helped.

1 Comment

These are the things I am looking for very well written details, I could care less about the answer I am looking to understand the problem to fully utilize and learn the language. Alok +1 plus accept for this thorough answer. You could write a book and I'd buy it.
0

In your function list_sort, the parameter is INTLIST *list.

list_map(aList[i], (void*)list_sort);

By looking at the header, the function prototype is a function pointer that has a parameter which is of type void *

void list_map(INTLIST* list, void (*f)(void *))
                                      ^^^^^^^^

The function pointer *f has to match up the signature, hence the conflict and the warning generated by your compiler. Since *f points to the list_sort, the method signature does not match up.

It would work if your function prototype has this instead

void list_map(INTLIST* list, void (*f)(INTLIST *))

Hope this helps, Best regards, Tom.

1 Comment

Cannot change the list_map prototype that was defined by the professor and we are not allowed to change those prototypes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.