Home > other >  C | Passing a function that has multiple parameters as a parameter
C | Passing a function that has multiple parameters as a parameter

Time:07-04

I have the following code:

typedef struct ll_node linked_list_node;
struct ll_node {
  int value;
  linked_list_node* next;
};

typedef struct ll linked_list;
struct ll {
  size_t size;
  linked_list_node* head;
  linked_list_node* tail;
};

void for_each(linked_list* list, void (*function)(linked_list_node*, ...)) {
  if (list == NULL || list->head == NULL) {
    return;
  }

  for (linked_list_node* node = list->head; node != NULL; node = node->next) {
    function(node, function->__va_arg_pack());
  }
}

What I mainly want to achieve is for_each to receive a function that is executed to every single linked list node, but I'm not sure if that can be achieved with functions that receive multiple parameters... Please help!

CodePudding user response:

I didn't explain myself very well. I'm building a linked list library for C (just as a hobby), and I want that library to have a for_each function that mainly executes something (another function) to every single nodes in the linked list

Just let user pass an additional void * argument. See for example at fopencookie or pthread_create or thrd_create.

int for_each(linked_list* list, int (*function)(linked_list_node *, void *cookie), void *cookie) {
   FOREACH_YOUR_LIST(i, list) {
       int ret = function(i, cookie);
       if (ret) { 
          // let users do early return
          return ret;
       }
   }
   return 0;
}
    

CodePudding user response:

If you are under gcc you can achieve that using statement expressions and nested functions, here an example of somtehing similar to a lambda.

In plain c is much more difficult and you would have to deal with NULL-terminated va_args lists and a lot of black magic. Another option is to use the preprocessor, also with its disadvantages, but at least the implementation is easier:

#define FOR_EACH(list, function, ...)                                            \
do {                                                                             \
    if (list == NULL || list->head == NULL) {                                    \
        break;                                                                   \
    }                                                                            \
    for (linked_list_node* node = list->head; node != NULL; node = node->next) { \
        function(node, __VA_ARGS__);                                             \
    }                                                                            \
} while (0)

void print(linked_list_node *node, int *count)
{
    printf("%d) %d\n", (*count)  , node->value);
}

void concat(linked_list_node *node, const char *str1, const char *str2)
{
    printf("%s %d %s\n", str1, node->value, str2);
}

int main(void)
{
    linked_list_node nodes[] = {{1, &nodes[1]} , {2, &nodes[2]}, {3, NULL}};
    linked_list *list = &(linked_list){3, &nodes[0], &nodes[2]};

    int count = 0;
    FOR_EACH(list, print, &count);
    FOR_EACH(list, concat, "Hi", "by");

    return 0;
}

Output:

0) 1
1) 2
2) 3
Hi 1 by
Hi 2 by
Hi 3 by
  • Related