1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | #include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include "clog.h"
// Linked list of strings on the heap
typedef struct _Node { // canonical type name is 'struct _Node'
// int value;
// char* value;
void* a_value; // address of ANYTHING
struct _Node* next;
} Node; // shortcut (typedef) name is 'Node'
void print_list(Node* head) {
for(Node* curr = head; curr != NULL; curr = curr -> next) {
//printf("[%d]", curr -> value); // v1 - linked list of ints
//printf("[%s]", curr -> value); // v2 - linked list of strings
printf("[%p]", (void*) curr -> a_value); // v3 - linked list of anything
printf(curr -> next != NULL ? "→" : "\n");
}
}
// void append(int value, Node** a_head, Node** a_tail) { // v1 - linked list of ints
// void append(char* value, Node** a_head, Node** a_tail) { // v2 - linked list of strings
void append(void* a_value, Node** a_head, Node** a_tail) { // v3 - linked list of anything
// 1. Allocate memory for the new node.
Node* new_tail = malloc(sizeof(*new_tail));
// 2. Initialize the fields of the new node.
// *new_tail = (Node) { .value = value, .next = NULL }; // v1 and v2
*new_tail = (Node) { .a_value = a_value, .next = NULL };// v3 - linked list of anything
// 3. Depending on whether or not the list was initially empty…
if(*a_head == NULL) { // If list is empty (size 0)…
// … Set the head (*a_head) to the (address of) the new tail, or …
*a_head = new_tail; // type of *a_head is Node*. type of new_tail is Node*.
}
else {
// … Connect the old tail to the new tail.
(*a_tail) -> next = new_tail;
}
// 4. Set the tail (*a_tail) to the (address of the) new tail.
*a_tail = new_tail;
// IMPORTANT: This must come last.
}
void destroy_list(Node** a_head, Node** a_tail) {
while(*a_head != NULL) { // While list is not empty…
Node* new_head = (*a_head) -> next; // 1. Save (address of) new head (or NULL)
//free((*a_head) -> a_value); // 2. Free whatever head node refers to.
free(*a_head); // 3. Free the old head.
*a_head = new_head; // 4. Set the head to the new_head.
}
*a_tail = NULL; // 5. Set the tail to NULL.
// Order is important. If we free before saving the (address of) new_head, we won't
// be able to access it.
assert(*a_head == NULL);
}
int main(int argc, char* argv[]) {
Node* head = NULL; // Linked list of size 0 (empty list)
Node* tail = NULL;
//char* s1 = "AB";
//char* s2 = "CD";
//char* s3 = "EF";
int n1 = 11;
int n2 = 12;
int n3 = 13;
//append(n1, &head, &tail);
append(&n1, &head, &tail);
assert(head == tail); // In a list of size 1, head and tail refer to the same Node.
append(&n2, &head, &tail);
assert(head != tail); // In a list of size 2, head and tail DON'T refer to the same Node
//assert(tail -> value == 11);
append(&n3, &head, &tail);
print_list(head);
destroy_list(&head, &tail);
assert(head == NULL);
assert(tail == NULL);
return EXIT_SUCCESS;
}
|
© Copyright 2022 Alexander J. Quinn This content is protected and may not be shared, uploaded, or distributed.