/* * https://grisha.org/blog/2013/04/02/linus-on-understanding-pointers/ */ #include #include #include #ifndef NNODES #define NNODES 25 #endif /* * non-list misc functions */ /** rand_int for use with shuffle */ static int rand_int (int n) { int limit = RAND_MAX - RAND_MAX % n, rnd; rnd = rand(); for (; rnd >= limit; ) rnd = rand(); return rnd % n; } /** shuffle integer array of size 'n' * (using fisher-yates method) */ void shuffle (int *a, int n) { int i, tmp; while (n-- > 1) { i = rand_int (n + 1); tmp = a[i]; a[i] = a[n]; a[n] = tmp; } } /* * list structs and functions */ typedef struct node_t { /* list node */ int data; struct node_t *prev, *next; } node_t; typedef struct { /* list wrapper with head & tail pointers */ node_t *head, *tail; size_t size; } list_t; /** create new node initialize all members */ node_t *createnode (int v) { node_t *node = malloc (sizeof *node); /* allocate node */ if (!node) { /* validate allocation */ perror ("malloc-node"); return NULL; } node->data = v; /* initialize members values */ node->prev = node->next = NULL; return node; /* return new node */ } /** add node at end of list, update tail to end */ node_t *add (list_t *l, int v) { node_t *node = createnode (v); /* allocate node */ if (!node) /* validate allocation */ return NULL; if (!l->head) /* if 1st node, node is head/tail */ l->head = l->tail = node; else { /* otherwise */ node->prev = l->tail; /* set prev to tail */ l->tail->next = node; /* add at end, update tail pointer */ l->tail = node; } l->size++; return node; /* return new node */ } /** add node in-order */ node_t *add_ordered (list_t *l, int v) { node_t **ppn = &l->head; /* pointer to pointer */ node_t *pn = l->head; /* pointer to node */ node_t *node = createnode (v); /* allocate node */ if (!node) /* validate allocation */ return NULL; l->size++; /* increment list size */ if (!l->head) { /* if 1st node, node is head/tail */ l->head = l->tail = node; return l->tail; } while (pn) { /* iterate over list */ if (v < pn->data) { /* if new node goes before current */ node->prev = (*ppn)->prev; /* set node prev to current prev */ *ppn = node; /* set current address to node */ pn->prev = node; /* set next->prev to current */ node->next = pn; /* set current->next to next */ return node; } ppn = &pn->next; /* get address of next node */ pn = pn->next; /* get next node pointer */ } node->prev = l->tail; l->tail->next = node; /* node goes at end, update tail pointer */ l->tail = node; return node; } /** print all nodes in list */ void prn (list_t *l) { if (!l->head) { puts ("list-empty"); return; } for (node_t *n = l->head; n; n = n->next) printf (" %d", n->data); putchar ('\n'); } /** print all nodes in list in reverse */ void prnrev (list_t *l) { if (!l->tail) { puts ("list-empty"); return; } for (node_t *n = l->tail; n; n = n->prev) printf (" %d", n->data); putchar ('\n'); } /** delete node with value v from list (for loop) */ void del_node (list_t *l, int v) { node_t **ppn = &l->head; /* pointer to pointer */ node_t *pn = l->head; /* pointer to node */ for (; pn; ppn = &pn->next, pn = pn->next) { if (pn->data == v) { *ppn = pn->next; /* set node at address to next */ if (pn != l->tail) /* prev is next prev */ (*ppn)->prev = pn->prev; else /* deleting tail, set tail to prev */ l->tail = pn->prev; free (pn); /* free current */ if (l->size) l->size--; else fputs ("error: size negative warning.\n", stderr); break; } } } /** delete all nodes in list */ void del_list (list_t *l) { node_t *n = l->head; while (n) { node_t *victim = n; n = n->next; free (victim); } l->head = l->tail = NULL; l->size = 0; } int main (void) { list_t l = { NULL, NULL, 0 }; /* initialize list pointers NULL */ int a[NNODES]; /* array to shuffle */ srand (time (NULL)); /* seed random number generator */ for (int i = 0; i < NNODES; i++) { /* fill array 1 - 10 */ // add (&l, i+1); a[i] = i+1; } shuffle (a, NNODES); /* shuffle array */ for (int i = 0; i < NNODES; i++) { /* add shuffled values in order */ #ifdef DEBUG printf ("adding : %d\n", a[i]); #endif // add (&l, a[i]); add_ordered (&l, a[i]); } printf ("list size: %zu\n\n", l.size); prn (&l); /* print list forward */ putchar ('\n'); prnrev (&l); /* print list reverse */ putchar ('\n'); add (&l, NNODES + 1); /* add at end for tail-pointer test */ printf ("list size: %zu\n\n", l.size); prn (&l); /* print list forward */ putchar ('\n'); prnrev (&l); /* print list reverse */ putchar ('\n'); del_node (&l, NNODES + 1); /* delete tail node */ printf ("list size: %zu\n\n", l.size); prn (&l); /* print list forward */ putchar ('\n'); prnrev (&l); /* print list reverse */ putchar ('\n'); shuffle (a, NNODES); /* shuffle array again */ for (int i = 0; i < NNODES; i++) { /* remove nodes in random order */ #ifdef DEBUG printf ("deleting: %d\n", a[i]); #endif del_node (&l, a[i]); } printf ("list size: %zu\n\n", l.size); prn (&l); /* print list ("list-empty") */ prnrev (&l); /* print list reverse ("list-empty") */ del_list (&l); /* delete list (does nothing list-empty) */ } /** delete node with value v from list (for loop) */ // void del_node (list_t *l, int v) // { // node_t **ppn = &l->head; /* pointer to pointer */ // node_t *pn = l->head; /* pointer to node */ // // for (; pn; ppn = &pn->next, pn = pn->next) { // if (pn->data == v) { // node_t *pprev = pn->prev; /* save current prev */ // *ppn = pn->next; /* set node at address to next */ // // if (pn == l->head) /* deleting head, prev is NULL */ // (*ppn)->prev = NULL; // else if (pn == l->tail) /* deleting tail, tail is prev */ // l->tail = pn->prev; // else /* set prev to saved prev */ // (*ppn)->prev = pprev; // // free (pn); /* free current */ // break; // } // } // }