1

This is my first question here. I'm unable to understand a couple line of codes in this program.

The custom destroy function pointer is what I'm unable to understand.

I've commented with "need help #1 and need help #2" where I need help with the codes.

Any help would be greatly appreciated and I will be really grateful to anyone who could help me understand these codes.

#ifndef LIST_H
#define LIST_H
#include <stdio.h>

typedef struct _ListElmt
{

  void *data;
  struct ListElmt *next;

} ListElmt;
typedef struct _List
{

  int size;
  int (*match)(const void *key1, const void *key2);
  void (*destroy)(void *data);

  ListElmt *head;
  ListElmt *tail;

} List;

void list_init(List *list, void (*destroy)(void *data));

void list_destroy(List *list);

int list_ins_next(List *list, ListElmt *element, const void *data);

int list_rem_next(List *list, ListElmt *element, void **data);

int list_size(const List *list);

ListElmt *list_head(const List *list);

ListElmt *list_tail(const List *list);

int list_is_head(const ListElmt *element);

int list_is_tail(const ListElmt *element);

void *list_data(const ListElmt *element);

ListElmt *list_next(const ListElmt *element);
#endif

and here is list.c

#include <stdlib.h>
#include <string.h>
#include "List.h"

/* Need Help #1: The destroy function pointer is called here when the list is initialized and I need some explanation on how this works */

void list_init(List *list, void (*destroy)(void *data))
{

  list->size = 0;
  list->destroy = destroy;
  list->head = NULL;
  list->tail = NULL;

  return;
}

void list_destroy(List *list)
{

  void *data;

  while (list_size(list) > 0)
  {

    if (list_rem_next(list, NULL, (void **) &data) == 0&& list->destroy != NULL)
    {

      list->destroy(data);

      /* Need Help #2: The above line - how this works. I have no idea how this works because I haven't seen any code like that before. Also kindly let me know if this is recursion or not.*/
    }
  }
  memset(list, 0, sizeof(List));
  return;
}

int list_ins_next(List *list, ListElmt *element, const void *data)
{

  ListElmt *new_element;

  if ((new_element = (ListElmt *) malloc(sizeof(ListElmt))) == NULL ) // not yet understanded
    return -1;

  new_element->data = (void *) data;

  if (element == NULL )
  {
    if (list_size(list) == 0)
      list->tail = new_element;

    new_element->next = list->head;
    list->head = new_element;
  }

  else
  {
    if (element->next == NULL )
      list->tail = new_element;

    new_element->next = element->next;
    element->next = new_element;
  }

  list->size++;
  return 0;
}

int list_rem_next(List *list, ListElmt *element, void **data)
{

  ListElmt *old_element;

  if (list_size(list) == 0)
    return -1;

  if (element == NULL )
  { // Handle removal of the head

    *data = list->head->data;
    old_element = list->head;
    list->head = list->head->next;

    if (list_size(list) == 1)
      list->tail = NULL;
  }

  else
  { // Handle removal from somewhere else

    if (element->next == NULL )
      return -1;

    *data = element->next->data;
    old_element = element->next;
    element->next = element->next->next;

    if (element->next == NULL )
      list->tail = element;
  }

  free(old_element);

  list->size--;
  return 0;
}
alk
  • 69,737
  • 10
  • 105
  • 255
LinuxPanda
  • 11
  • 2
  • 1
    possible duplicate of [How do function pointers in C work?](http://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work) – Shahbaz Sep 29 '13 at 13:45
  • you want help but what is your question please clarify? – Tonmoy Sep 29 '13 at 13:46

2 Answers2

3

For question #1

The argument destroy passed to the linked list on creation is pointer to a function. The linked doesn't know how to destroy the objects it holds and thus free the memory. So it needs something from outside to perform that action for it. So you as user have to write a function which knows how to free the memory of the object you save in the list, and tell the linked list to use that function when it needs to destroy a node.

The pointer to the function is saved in the list variable destroy.

For question #2

The function to which you have passed a pointer to is just called and is being passed a pointer to the data stored in the current node in order to free the memory it occupies.

This technique is referred to as command or action pattern (it is not only restricted to oop!)

A4L
  • 17,353
  • 6
  • 49
  • 70
0
  • #help1 := nothing is called; the function pointer is only assigned to: after the assignment list->destroy contains the address of the destroy function.
  • #help2 := now the function is called: func(arg) is a function call, and so is funcptr(arg), if fncptr is a pointer to function type
  • #help3 := memset(list, 0, sizeof(List)); falsely assumes that a NULL pointer value is represented by all-zeros. It need not be. (in most cases it is, but an achitecture may have a different representation for NULL )
wildplasser
  • 43,142
  • 8
  • 66
  • 109