Home > OS >  Function with parameters but no arguments
Function with parameters but no arguments

Time:09-05

I was reading a mergeSort from standard library in c and found that it has a compare function as an argument(i.e void msort(void *base, size_t nitems, size_t size, int (*compar)(const void , const void)) when it's defined). However, in actual use when the msort function is called, compar function didn't have an argument passed to it(even though it had two parameters, which are (const void *, const void *) as parameters. look the ff code snippet and I would appreciate how it's possible for a function with parameters to be used without arguments in the time it's called??

#include <stdio.h>
#include <stdlib.h>

int values[] = { 88, 56, 100, 2, 25 };

int cmpfunc (const void * a, const void * b) {
   return ( *(int*)a - *(int*)b );
}

int main () {
   int n;

   printf("Before sorting the list is: \n");
   for( n = 0 ; n < 5; n   ) {
      printf("%d ", values[n]);
   }

   msort(values, 5, sizeof(int), cmpfunc);

   printf("\nAfter sorting the list is: \n");
   for( n = 0 ; n < 5; n   ) {   
      printf("%d ", values[n]);
   }
  
   return(0);
}

CodePudding user response:

This is a so called a function pointer: you're basically passing the function cmpfunc() as a parameter, which will then be used by the msort() function internally, with the proper arguments.

A function pointer is a variable that stores the address of a function that can later be called through that function pointer. This is useful because functions encapsulate behavior.

Function pointers are the precursors of function closures.


To be more clear: the reason why it has no arguments is because you don't know them yet.
Let me explain: cmpfunc() serves to compare 2 elements and tell which one precedes the other. But msort() will need to do many different comparisons, since it has to iterate over all the elements of values[]. Therefore, internally msort() is going to select 2 elements at a time, let's call them x and y, compare them cmpfunc(x, y) and swap them if needed.

CodePudding user response:

void msort(void *base, size_t nitems, size_t size, int (*compar)(const void* , const void*)) 

The function msort takes a function pointer as its final argument. Just like regular paramters, this parameter tells the msort function that "an address of a function which itself takes two const void* as an argument and retuns an int" will be passed as a parameter. When called like:

msort(values, 5, sizeof(int), cmpfunc);

without the paranthesis at the end of cmpfunc, you are just passing the address of cmpfunc and not actually calling it, therefore it doesn't make sense to pass parameters anyway. You are merely telling the msort where to find the function.

Who actually calls the cmpfunc is the msort. If you have access to its source, you probably can see when and how it calls it (with appropriate parameters passed).

CodePudding user response:

I won't repeat what others have correctly described about "passing the address of a function as a parameter to another function."

A "use case" may help you understand "WHY?"

From your example:

int cmpAscending (const void * a, const void * b) {
    return ( *(int*)a - *(int*)b );
}

Now, a "twin" of that:

int cmpDescending (const void * a, const void * b) {
    return ( *(int*)b - *(int*)a );  // NB: subtle difference
}

Now, a program can pass the address of the appropriate compare function to msort().

if( ascending )
    msort( values, 5, sizeof(int), cmpAscending );
else
    msort( values, 5, sizeof(int), cmpDescending );

There are even more economical ways to achieve this:

    msort( values, 5, sizeof(int), ascending ? cmpAscending : cmpDescending );

CodePudding user response:

An example, in the main function, foo receives the address of the bar function. Then function foo can call function bar via the function pointer pbar that it received as an argument:

#include <stdio.h>

void bar(int x )
{
    printf("%d\n", x);
}

void foo(void(*pbar)(int))
{
    pbar(10);
    pbar(20);
}

int main(void)
{
   foo(bar);

   return(0);
}
  • Related