llwfp

Documentation
Login

Documentation

/*
   Compile:
   make readme-ex02-using-voidp
 */

#define _BSD_SOURCE /* snprintf() */

#include <string.h> /* memcpy() */
#include <stdio.h>  /* printf() */
#include <stdlib.h> /* calloc() */

#define MAXSIZE 256

/* Generic node struct, using a void pointer for data */
typedef struct node_t
{
  struct node_t *next;
  void *data; /* GENERIC */
} node_t;

/* Definitions for the struct example */
/* HTML header levels */
typedef enum header_level
{
  h1 = 1,
  h2,
  h3,
  h4,
  h5,
  h6
} header_level;
/* HTML header typedef */
typedef struct html_header
{
    header_level level;
    char *title;
} html_header;

/* Definition for the double array example */
typedef struct double_arr_t
{
  double *arr_data;
  size_t arr_len;
} double_arr_t;

/* Add node with data - int */
node_t *node_add_int(node_t **current_node, int data)
{
  node_t *node = *current_node;
  node->data = calloc(1, sizeof(data));
  memcpy(node->data, &data, sizeof(data));  /* WORKS AS EXPECTED */
  node->next = calloc(1, sizeof(*node));
  node = node->next;
  return node;
}

/* Add node with data - char * */
node_t *node_add_char_p(node_t **current_node, int i)
{
  node_t *node = *current_node;
  char buf[MAXSIZE] = {0};
  size_t buf_size = 0;
  snprintf(buf, MAXSIZE, "%d", i);
  buf_size = sizeof(char) * (strlen(buf) + 1);
  node->data = calloc(1, buf_size);
  memcpy(node->data, buf, buf_size);
  node->next = calloc(1, sizeof(*node));
  node = node->next;
  return node;
}

/* Add node with data - struct */
node_t *node_add_struct(node_t **current_node, int i)
{
  html_header *header = NULL;
  char buf[MAXSIZE] = {0};
  size_t buf_size = 0;
  header_level level = h1 + i % h6;
  char *title = NULL;
  node_t *node = *current_node;
  snprintf(buf, MAXSIZE, "This is title %d", i);
  buf_size = sizeof(char) * (strlen(buf) + 1);
  title = calloc(1, buf_size);
  memcpy(title, buf, buf_size);
  header = calloc(1, sizeof(*header));
  header->level = level;
  header->title = title;
  node->data = header;
  node->next = calloc(1, sizeof(*node));
  node = node->next;
  return node;
}

/* Add node with data - double[] */
node_t *node_add_double_arr(node_t **current_node, int i)
{
  double_arr_t *arr = NULL;
  double arr_data[] = {0, 97.0, 33.0, 31.0, 96.0, 30.0, 36.0, 92.0};
  size_t arr_len = sizeof(arr_data)/sizeof(arr_data[0]);
  node_t *node = *current_node;
  arr_data[0] = (double)i;
  arr = calloc(1, sizeof(*arr));
  arr->arr_data = calloc(1, sizeof(arr_data));
  memcpy(arr->arr_data, arr_data, sizeof(arr_data));
  arr->arr_len = arr_len;
  node->data = arr;
  node->next = calloc(1, sizeof(*node));
  node = node->next;
  return node;
}

/* Get a node by index */
node_t *node_get_by_index(node_t *head, int node_index)
{
  node_t *node = head;
  int i = 0;
  for (i = 0; i < node_index; ++i)
  {
    node = node->next;
  }
  return node;
}

/* Print data for a node - int * */
void node_print_int(node_t *node, const char *fmt_str)
{
  printf(fmt_str, *(int *)node->data);
}

/* Print data for a node - char * */
void node_print_char_p(node_t *node, int node_index)
{
  printf("node%d->data='%s'\n", node_index, (char *)node->data);
}

/* Print data for a node - struct */
void node_print_struct(node_t *node, int node_index)
{
  printf("node%d->data->level=%d, \t", node_index, ((html_header *)node->data)->level);
  printf("node%d->data->title='%s'\n", node_index, ((html_header *)node->data)->title);
}

/* Print data for a node - array of double */
void node_print_double_array(node_t *node, int node_index)
{
  int i = 0;
  printf("node%d->data= {", node_index);
  for (i = 0; i < (int)((double_arr_t *)node->data)->arr_len; ++i)
  {
    if (i) printf(", ");
    printf("%.1f", (double)((double_arr_t *)node->data)->arr_data[i]);
  }
  printf("}\n");
}

/* Delete all nodes */
void node_cleanup(node_t **head)
{
  node_t *current = *head, *next = NULL;
  while (current)
  {
    /* Free data, assume calloc() was called */
    free(current->data);
    next = current->next;
    free(current);
    current = next;
  }
   /* Set variable to NULL *before* free(). */
   /* Valgrind doesn't like it the other way around! */
  *head = NULL;
  free(*head);
}

/* Delete all nodes, consider additional struct data */
void node_cleanup_struct(node_t **head)
{
  node_t *current = *head, *next = NULL;
  while (current)
  {
    html_header *header = (html_header *)current->data;
    /* Free data, assume calloc() was called both for node data and struct member */
    if ((header) && (header->title)) free(header->title);
    free(current->data);
    next = current->next;
    free(current);
    current = next;
  }
   /* Set variable to NULL *before* free(). */
   /* Valgrind doesn't like it the other way around! */
  *head = NULL;
  free(*head);
}

/* Delete all nodes, consider additional struct data */
void node_cleanup_double_array(node_t **head)
{
  node_t *current = *head, *next = NULL;
  while (current)
  {
    double_arr_t *arr = (double_arr_t *)current->data;
    /* Free data, assume calloc() was called both for node data and struct member */
    if ((arr) && (arr->arr_data)) free(arr->arr_data);
    free(current->data);
    next = current->next;
    free(current);
    current = next;
  }
   /* Set variable to NULL *before* free(). */
   /* Valgrind doesn't like it the other way around! */
  *head = NULL;
  free(*head);
}

/* Delete all nodes, don't consider data */
void node_but_not_data_cleanup(node_t **head)
{
  node_t *current = *head, *next = NULL;
  while (current)
  {
    next = current->next;
    free(current);
    current = next;
  }
   /* Set variable to NULL *before* free(). */
   /* Valgrind doesn't like it the other way around! */
  *head = NULL;
  free(*head);
}

int
main(int argc, char *argv[])
{
  node_t *node1 = calloc(1, sizeof(*node1));
  node_t *node2 = calloc(1, sizeof(*node2));
  node_t *node3 = calloc(1, sizeof(*node3));

  node_t *node_dont       = calloc(1, sizeof(*node_dont));
  node_t *node_do         = calloc(1, sizeof(*node_do));
  node_t *node_char_p     = calloc(1, sizeof(*node_char_p));
  node_t *node_struct     = calloc(1, sizeof(*node_struct));
  node_t *node_double_arr = calloc(1, sizeof(*node_double_arr));

  node_t *node = NULL;

  const int data1 = 12;
  const char *data2 = "99";
  const double data3 = 37.0;

  int i = 0;

  printf("\nREADME EX02\n");
  printf("----------------------------------------\n");

  node1->data = (void *)&data1;
  node2->data = (void *)&data2;
  node3->data = (void *)&data3;

  node1->next = node2;
  node2->next = node3;
  node3->next = NULL;

  printf("\nEX02, list 1: Using 'void *', data types may be mixed in the same list\n");
  printf("----------------------------------------------------------------------\n");
  printf("int    :\tnode1->data=%d\n", *(int *)node1->data);
  printf("char * :\tnode1->next->data='%s'\n", *(char **)node1->next->data);
  printf("double :\tnode1->next->next->data=%f\n", *(double *)node1->next->next->data);

  printf("\nEX02, list 2: DON'T! Use a loop variable and point variable to node data. DON'T!\n");
  printf("--------------------------------------------------------------------------------\n");
  printf("node->data = (void *)&i; /* DOES NOT WORK AS EXPECTED! */ \n");
  node = node_dont;
  for (i = 0; i < 100; ++i)
  {
    node->data = (void *)&i; /* NOT WORKING AS EXPECTED */
    node->next = calloc(1, sizeof(*node));
    node = node->next;
  }
  /* Print node 42 of 100 - should print 42 */
  node = node_get_by_index(node_dont, 42);
  node_print_int(node, "node->data=%d\thuh? is this node 42?\n");
  i = 666;
  node_print_int(node, "node->data=%d\tevil surprise! :-(\n");


  printf("\nEX02, list 3: DO! Use a loop variable and allocate node data memory for each value. DO!\n");
  printf("---------------------------------------------------------------------------------------\n");
  printf("memcpy(node->data,  &i, sizeof(i)); /* WORKS AS EXPECTED */\n");
  node = node_do;
  for (i = 0; i < 100; ++i)
  {
    node = node_add_int(&node, i);
  }
  /* Print node 42 of 100 - should print 42 */
  node = node_get_by_index(node_do, 42);
  node_print_int(node, "node->data=%d\tOK, this looks more like node 42\n");
  i = 666;
  node_print_int(node, "node->data=%d\tno evil surprise\n");
  printf("Following 3 nodes:\n");
  node_print_int(node->next, "node43->data=%d\n");
  node_print_int(node->next->next, "node44->data=%d\n");
  node_print_int(node->next->next->next, "node45->data=%d\n");
  printf("First 3 nodes:\n");
  node = node_do;
  node_print_int(node, "node0->data=%d\n");
  node_print_int(node->next, "node1->data=%d\n");
  node_print_int(node->next->next, "node2->data=%d\n");

  printf("\nEX02, list 4: Data type: char *\n");
  printf("-------------------------------\n");
  node = node_char_p;
  for (i = 0; i < 100; ++i)
  {
    node = node_add_char_p(&node, i);
  }
  /* Print node 42 of 100 - should print '42' */
  node = node_get_by_index(node_char_p, 42);
  node_print_char_p(node, 42);
  printf("Following 3 nodes:\n");
  node_print_char_p(node->next, 43);
  node_print_char_p(node->next->next, 44);
  node_print_char_p(node->next->next->next, 45);
  printf("First 3 nodes:\n");
  node = node_char_p;
  node_print_char_p(node, 0);
  node_print_char_p(node->next, 1);
  node_print_char_p(node->next->next, 2);

  printf("\nEX02, list 5: Data type: struct\n");
  printf("-------------------------------\n");
  node = node_struct;
  for (i = 0; i < 100; ++i)
  {
    node = node_add_struct(&node, i);
  }
  /* Print node 42 of 100 - should print 'This is title 42' */
  node = node_get_by_index(node_struct, 42);
  node_print_struct(node, 42);
  printf("Following 3 nodes:\n");
  node_print_struct(node->next, 43);
  node_print_struct(node->next->next, 44);
  node_print_struct(node->next->next->next, 45);
  printf("First 3 nodes:\n");
  node = node_struct;
  node_print_struct(node, 0);
  node_print_struct(node->next, 1);
  node_print_struct(node->next->next, 2);

  printf("\nEX02, list 6: Data type: double[]\n");
  printf("---------------------------------\n");
  node = node_double_arr;
  for (i = 0; i < 100; ++i)
  {
    node = node_add_double_arr(&node, i);
  }
  /* Print node 42 - should print "node42->data= {42.0, 97.0, 33.0, 31.0, 96.0, 30.0, 36.0, 92.0}" */
  node = node_get_by_index(node_double_arr, 42);
  node_print_double_array(node, 42);
  printf("Nodes 43, 44, 45:\n");
  node_print_double_array(node->next, 43);
  node_print_double_array(node->next->next, 44);
  node_print_double_array(node->next->next->next, 45);
  printf("Nodes 0, 1, 2:\n");
  node = node_double_arr;
  node_print_double_array(node, 0);
  node_print_double_array(node->next, 1);
  node_print_double_array(node->next->next, 2);

  /* Cleanup all lists */
  node_but_not_data_cleanup(&node1);
  node_but_not_data_cleanup(&node_dont);
  node_cleanup(&node_do);
  node_cleanup(&node_char_p);
  node_cleanup_struct(&node_struct);
  node_cleanup_double_array(&node_double_arr);

  printf("\nTIP: MEMLEAK CHECK:\n");
  printf("valgrind -v --track-origins=yes --leak-check=full --show-leak-kinds=all %s\n", argv[0]);
  (void)argc;

  printf("----------------------------------------\n");

  return 0;
}