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 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | #include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include "clog.h"
typedef struct {
int x;
int y;
} Point;
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_as_addresses(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);
}
//void print_list_of_anything(Node const* head, void (*print_fn)(Point*)) {
void print_list_of_anything(Node const* head, void (*print_fn)(void*)) {
for(Node const* curr = head; curr != NULL; curr = curr -> next) {
printf("[");
print_fn(curr -> a_value); // Call function that prints this type of value
printf("] ");
}
printf("\n");
}
// void print_point(Point* a_point) {
// // parameter Point* a_point doesn't fit void* in print_list_of_anything
void print_point(void* a_point) {
printf("x==%d y==%d", a_point -> x, a_point -> y);
}
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;
Point p1 = { .x = 5, .y = 7 };
Point p2 = { .x = 9, .y = 11 };
Point p3 = { .x = 13, .y = 15 };
//append(n1, &head, &tail);
//append(&n1, &head, &tail);
append(&p1, &head, &tail);
assert(head == tail); // In a list of size 1, head and tail refer to the same Node.
append(&p2, &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(&p3, &head, &tail);
print_list_as_addresses(head);
print_list_of_anything(head, print_point);
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.