stack

Run Settings
LanguageC
Language Version
Run Command
/* Stack implemented as a linked list. * Node, struct node_s - next: pointer to next node - item: payload * List, struct list_s - head: pointer to first node - len : size of the list i.e. number of nodes * List methods: - size: get len method, `list.len(self)` - push: list_push method, `list.push(self, 5)` * Functions/quasi methods: - node_new - node_drop - list_new - list_len - list_push - list_pop - list_print - list_drop GENERIC LIST? Generic list i.e. generic payload - generics with macros or by adding more params to fns i.e. delegating more responsibility to the caller? - fns must take additional params to know payload size, type - does payload live on the stack or heap? who will free it if on the heap? - should fns take payload by value or by ref? - too many complications, too much relies on the caller ... fuck it: make payload an i32, list on stack, nodes on heap. UTILITIES: i32 Length(struct node* head); struct node* BuildOneTwoThree(); // Allocates and returns the list {1, 2, 3}. void Push(struct node** headRef, i32 newData); Given an i32 and a reference to the head pointer (i.e. a struct node** pointer to the head pointer), add a new node at the head of the list with the standard 3-step-link-in: - create the new node - set its .next to point to the current head - change the head to point to the new node. USAGE: Push(&head, 13); //: {13, 1, 2, 3} // '&' used cuz the head is passed as a reference pointer struct node* head = BuildOneTwoThree(); //: {1, 2, 3} Push(&(head->next), 42); //: {13, 42, 1, 2, 3} // Push 42 into the second position. Shows the use of '&' on `next` field i32 len = Length(head); //: 5 */ #include <stdio.h> #include <stdbool.h> #include <stdint.h> #include <stddef.h> #include <assert.h> #include <stdlib.h> // ====================================================== PROTOTYPES #define usize size_t #define i32 int32_t #define NONE INT32_MAX // forward declarations struct node_s; struct list_s; // aliases: bring identifiers from tag into ordinary namespace typedef struct node_s Node; typedef struct list_s List; // function prototypes (param names may be omitted) Node* node_new(Node* next, i32 item); Node* node_drop(Node* node); List list_new(); i32 list_pop(List* list); usize list_len(List* list); List* list_drop(List* list); List* list_push(List* list, i32 item); List* list_print(List* list); // ====================================================== DECLARATIONS /* Node is an element of the list that carries a payload. Nodes are stored on the heap. */ struct node_s { Node *next; // 8 i32 item; // 4 i32 hits; // 4 }; /* List consists of nodes. List itself is stored on the stack. List manages nodes and methods. It points to the first node. */ struct list_s { Node *head; usize length; // quasi methods usize (*len)(List*); List *(*push)(List*, i32); List *(*drop)(List*); List *(*print)(List*); i32 (*pop)(List*); }; // ===================================================== NODE NEW /** * Creates a new node with supplied item. * * @param Node* next Takes a reference to (the next) node. * @param i32 item Takes a payload by value. * @return Node* Reference to new node or NULL on error. **/ Node* node_new(Node* next, i32 item) { Node* np = malloc(sizeof *np); if(np != NULL) { np->next = next; np->item = item; np->hits = 0; } // ref to node or NULL if allocation failed return np; } // ===================================================== LIST NEW /** * Creates a new empty list on the stack. * * @return List Returns the new list by value. **/ List list_new() { // Initialize new list List list = { .head = NULL, .length = 0, .len = list_len, .push = list_push, .pop = list_pop, .print = list_print, .drop = list_drop }; return list; } // ===================================================== NODE DROP /** * Deallocates a node. * * @param Node* node Takes a node by reference. * @return Node* Returns a reference to the next node in sequence. **/ Node* node_drop(Node* node) { // temp node ptr Node* np = NULL; // check supplied node ref if(node != NULL) { // save its `next` value np = node->next; // drop it free(node); } // return a ref to next node. Or NULL on failure? (TODO) what if // that was the last node? NULL gets returned in either case... return np; } // ===================================================== LIST DROP /** * Iteratively deallocates all nodes in the list. * Empties the list. * * @param List* list Takes list reference. * @return List* Returns list reference. **/ List* list_drop(List* list) { // take each node starting with head and call node_drop, // which drops the current and returns a ref to the next. Node *np = list->head; while(np != NULL) { np = node_drop(np); } list->head = NULL; return list; } // ===================================================== LIST: POP /* * Removes the head node and returns its payload. * * @param List* list Takes list reference. * @return i32 Payload by value or NONE if list empty. */ i32 list_pop(List* list) { if (list->head != NULL) { // at least 1 node i32 rv = list->head->item; list->head = node_drop(list->head); list->length--; return rv; } // in-band signaling: no payload to return return NONE; } // ===================================================== LIST PUSH /* * Insert new node at the front of the list. * * @param List* list Takes a list by reference. * @param i32 item Takes a payload by value. * @return List* Returns the list by reference. */ List* list_push(List* list, i32 item) { // alloc new node, set current head as its next, may be NULL Node* new_node = node_new(list->head, item); // check alloc of new node assert(new_node != NULL); // set new node as new head list->head = new_node; // set new length list->length++; return list; } // ===================================================== LIST LEN /* * Get list's length. * * @param List* list Takes list by reference. * @return usize Number of nodes in the list. */ usize list_len(List* list) { return list->length; } // ===================================================== LIST PRINT /* * Display list. * * @param List* list Takes list reference. * @return List Returns list reference. */ List* list_print(List* list) { Node *np = list->head; i32 i = 1; printf("List: "); while(np != NULL) { printf("[%d: %d] -> ", i++, np->item); np = np->next; } printf("NULL\n\n"); return list; } // ===================================================== MAIN int main() { // new: list, list ref List list = list_new(), *self = &list; assert(list.len(self) == 0); // push quasi method list.push(self, 99); assert(list.len(self) == 1); // method chaining list.push(self, 88)->push(self, 77)->push(self, 66)->print(self); // len: quasi method printf("List length: %zu\n", list.len(self)); // print quasi method list.print(self); // pop quasi method i32 x; while ( (x = list.pop(self)) != NONE ) { printf("popped: %d\n", x); list.print(self); } // drop quasi method list.drop(self)->print(self)->push(self, 5)->push(self, 4)->print(self); printf("so far so good\n"); return 0; }
Editor Settings
Theme
Key bindings
Full width
Lines