Search code examples
cparametersfunction-declaration

About function pointers in C


what is the magic on the finding function below?

1) what is this inner mechanism that allows match to be used without being declared previously?

2) In main , shouldn't the finding call pass the array ADS along with sports_no_trucks?

Thanks in advance!

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

int NUM_ADS = 2;
char *ADS[] = {
    "Luis: SLM ND likes sports, theater, art",
    "Mike: DWM DS likes trucks, sports"
};

void finding(int (*match) (char *))
{
    int i;
    puts("Search results:");
    puts("------------------------------------");
    for (i = 0; i < NUM_ADS; i++)
    {
        if (match(ADS[i]))
        {
            printf("%s\n", ADS[i]);
        }
    }
    puts("------------------------------------");
}

int sports_no_trucks(char *s)
{
    return strstr(s, "sports") && !strstr(s, "trucks");
}


int main()
{

    finding(sports_no_trucks);
    return 0;
}

Solution

  • In this function declaration

    void finding(int (*match) (char *));
    

    there is declared one parameter with the name match that has the type of pointer to function of the type int( char * ). That is the parameter match itself has the type int ( * )( char * ).

    In the call of the function finding

    finding(sports_no_trucks);
    

    there is passed as an argument function designator sports_no_trucks that corresponds to the following definition of the function

    int sports_no_trucks(char *s)
    {
        return strstr(s, "sports") && !strstr(s, "trucks");
    }
    

    So the parameter match of the function finding gets the value of the pointer to the function sports_no_trucks because function designators used in expressions are converted to pointers to functions.

    You can imagine the definition of the function finding and its call the following way

    finding(sports_no_trucks);
    
    //...
    
    void finding( /* int (*match) (char *) */ )
    {
        int ( *match )( char * ) = sports_no_trucks;
        //...
    }
    

    To make it more clear you can introduce a typedef name like

    typedef int FN( char * );
    

    In this case the declaration of the function finding will look like

    void finding( FN *match );
    

    where FN is an alias for the function type int( char * ).

    2) In main , shouldn't the finding call pass the array ADS along with sports_no_trucks?

    The array declared as a global variable

    int NUM_ADS = 2;
    char *ADS[] = {
        "Luis: SLM ND likes sports, theater, art",
        "Mike: DWM DS likes trucks, sports"
    };
    

    And the function finding has access to it because it is visible in the file scope of the program

    for (i = 0; i < NUM_ADS; i++)
    {
        if (match(ADS[i]))
        {
            printf("%s\n", ADS[i]);
        }
    }
    

    But you are right. It is a bad style of programming when functions depend on global variables. In this case you are unable to call the function for another array. So this function is not a general function. It is very specific and can deal with only one array.

    There was no need to declare the array as global and define the function that depends on the global array.

    In this case the function declaration can look like

    void finding( char * s[], size_t n, int (*match) (char *));
    

    and the function could be called for the array ADS like

    finding( ADS, NUM_ADS, sports_no_trucks );
    

    But it could be called for any other array the same way

    finding( AnotherArray, ItsSize, sports_no_trucks );