#include #include "stack.h" // Pushes data as pointer onto the stack. // Parameters: // - stack: pointer to the current top of the stack (can be NULL if stack is empty) // - data: void pointer to the data to be pushed onto the stack // Returns: pointer to the new top of the stack (the newly created node) // Note: The function allocates memory for a new StackNode, sets its data pointer // and links it to the previous top, making it the new top of the stack. StackNode *push(StackNode *stack, void *data) { // Allocate memory for a new StackNode StackNode *newNode = (StackNode *)malloc(sizeof(StackNode)); // Check if memory allocation was successful if (newNode == NULL) { return NULL; // Return NULL if allocation failed } // Store the data pointer in the new node newNode->data = data; // Link the new node to the previous top of the stack // If stack was NULL (empty), newNode->next will be NULL // If stack was not NULL, newNode->next points to the old top newNode->next = stack; // Return the new node, which is now the new top of the stack return newNode; } // Deletes the top element of the stack (latest added element) and releases its memory. // Parameters: // - stack: pointer to the current top of the stack // Returns: pointer to the new top of the stack (the second element, or NULL if stack becomes empty) // Note: This function only frees the StackNode structure itself. The caller is responsible // for freeing the data that the node was pointing to, if that data was dynamically allocated. StackNode *pop(StackNode *stack) { // Check if the stack is empty if (stack == NULL) { return NULL; // Cannot pop from an empty stack } // Save a pointer to the next node (which will become the new top) StackNode *newTop = stack->next; // Free the memory of the current top node // NOTE: We do NOT free stack->data here because the caller may still need it // or may be responsible for freeing it themselves free(stack); // Return the new top of the stack (or NULL if the stack is now empty) return newTop; } // Returns the data of the top element without removing it from the stack. // Parameters: // - stack: pointer to the current top of the stack // Returns: void pointer to the data of the top element, or NULL if stack is empty // Note: This is a "peek" operation - it looks at the top without removing it. void *top(StackNode *stack) { // Check if the stack is empty if (stack == NULL) { return NULL; // Return NULL if stack is empty } // Return the data pointer stored in the top node // The caller can then use this pointer to access the actual data return stack->data; } // Clears the entire stack and releases all memory used by the StackNodes. // Parameters: // - stack: pointer to the current top of the stack // Returns: void // Note: This function only frees the StackNode structures. The caller is responsible // for freeing any dynamically allocated data that the nodes were pointing to, // unless that is done elsewhere in the program before calling clearStack. void clearStack(StackNode *stack) { // Base case: if the stack is NULL (empty), we're done if (stack == NULL) { return; } // Recursive case: first, recursively clear all the nodes below this one // This processes the stack from top to bottom clearStack(stack->next); // After recursively clearing all deeper nodes, free the current node free(stack); }