比较函数作为稍后使用的参数

Comparison function as argument to use later on

我正在研究通用二叉搜索树,但我很难理解 parameter/argument 传递函数在 C 中的工作原理。 我想告诉我的通用 BST,它必须在需要比较时使用 compare_doubles()。

当我在 createBST() 中创建空 BST 时,如何在代码中的某处实例化函数指针?

鉴于此 BST.h :

#include <stddef.h>
#include <stdbool.h>

typedef struct tree_t BinarySearchTree;

/* ------------------------------------------------------------------------- *
 * Creates an empty BST.
 * ARGUMENT
 * comparison_fn_t      A comparison function
 * BinarySearchTree bst = newBST(&compare_doubles);
 * ------------------------------------------------------------------------- */

BinarySearchTree* createBST(int comparison_fn_t(const void *, const void *));
bool insertInBST(BinarySearchTree* bst, const void* key, const void* value);

BST.c :

#include <stddef.h>
#include <stdlib.h>
#include "BinarySearchTree.h"

struct tree_t {
    const void *key;
    const void *value;
    const void *leftChild;
    const void *rightChild;
    //const void *comparison_fn_t; //try to have it as an argument 1st try
};

//int (*compare) (const void *, const void *); //try to save it for later 2nd try

BinarySearchTree* newBST(int comparison_fn_t(const void*, const void*)) {
    BinarySearchTree *binarySearchTree = malloc(sizeof(BinarySearchTree));
    if (!binarySearchTree)
        return NULL;
    binarySearchTree->value = NULL;
    binarySearchTree->key = NULL;
    binarySearchTree->leftChild = NULL;
    binarySearchTree->rightChild = NULL;
    compare = &comparison_fn_t; //1st try
    //binarySearchTree->comparison_fn_t = comparison_fn_t //2nd try
    return binarySearchTree;
}
bool insertInBST(BinarySearchTree* bst, const void* key, const void* value) {
    //other code
    int val = (*compare) (key, bst->key); //1st try
    int val = bst->comparison_fn_t... //2nd try
}

在我的 Main.c 中:

int compare_doubles(const void *a, const void *b) {
    const double *a_ = (const double*) a;
    const double *b_ = (const double*) b;
    return (*a_ > *b_) - (*a_ < *b_);
}

BinarySearchTree *searchTree= createBST(&compare_doubles);
insertInBST(searchTree, key, value);

只需在结构中使用相同的函数指针定义:

struct tree_t {
    const void *key;
    const void *value;
    const void *leftChild;
    const void *rightChild;
    int (*comparison_fn)(const void*, const void*);
};

BinarySearchTree* newBST(int (*comparison_fn)(const void*, const void*)) {
    
    ...
    // assign the fn pointer here
    binarySearchTree->comparison_fn = comparison_fn;
    return binarySearchTree;
}

为了使语法更简单,您可以使用 typedef:

typedef int (*BinaryComparison)(const void*, const void*); 

struct tree_t {
    const void *key;
    const void *value;
    const void *leftChild;
    const void *rightChild;
    BinaryComparison comparison_fn;
};

BinarySearchTree* newBST(BinaryComparison comparison_fn) {
    BinarySearchTree* binarySearchTree = malloc(sizeof *binarySearchTree);
    binarySearchTree->comparison_fn = comparison_fn;
    return binarySearchTree;
}

对于初学者来说,不清楚为什么数据成员 leftChildrightChild 具有类型 const void * 而不是类型 struct tree_t *.

struct tree_t {
    const void *key;
    const void *value;
    const void *leftChild;
    const void *rightChild;
    //const void *comparison_fn_t; //try to have it as an argument 1st try
};

此外,将指向函数的指针存储为该结构的数据成员也没有什么意义,因为在这种情况下,该数据成员将在二叉树的每个节点中重复。

您可以再声明一个结构,例如

struct node_t {
    const void *key;
    void *value;
    struct node_t *leftChild;
    struct Node_t *rightChild;
};

struct tree_t {
    struct node_t *head;
    int ( *comparison )( const void *, const void * );
};

typedef struct tree_t BinarySearchTree;

在这种情况下,您可以通过以下方式创建 struct tree_t 类型的对象

BinarySearchTree * createBST( int comparison( const void *, const void * ) )    
{
    BinarySearchTree *tree = malloc( sizeof( *tree ) );

    if ( tree != NULL )
    {
        tree->head = NULL;
        tree->comparison = comparison;
    }

    return tree;
}

int compare_doubles(const void *a, const void *b) {
    const double *a_ = (const double*) a;
    const double *b_ = (const double*) b;
    return (*a_ > *b_) - (*a_ < *b_);
}


int main( void )
{
    BinarySearchTree *tree = createBST( compare_doubles );
    //...
}