Stack in C: Concept, Operations, and Code Implementation

Updated on 01/09/20258,012 Views

How do you store data in reverse order using C—so the last item is the first out?

You use a stack in C, a classic Last-In, First-Out (LIFO) data structure.

A stack in C stores data elements sequentially and allows operations like push (add), pop (remove), peek (view top), and display. It’s commonly implemented using arrays or linked lists. Stacks are used in recursion tracking, expression evaluation, undo features, and many algorithmic problems.

In this tutorial, you’ll learn how to implement a stack in C using arrays. We'll walk through each operation, explain the logic behind it, and provide clean, testable code examples. You’ll also learn how to handle stack overflow and underflow conditions—two common issues when dealing with limited memory.

By the end, you’ll be confident in building and using stacks in your own C programs.

Want to explore more essential data structures in C? Enroll in our Software Engineering Courses for hands-on learning and real-world applications.

Representing a Stack in C

In C, a stack can be represented using either an array or a linked list. An array-based implementation is straightforward and useful for stacks of fixed size, while a linked list implementation is dynamic and allows for a flexible size.

Gain in-demand expertise in Cloud Computing, DevOps, and AI-powered Full Stack Development with cutting-edge programs from top institutions. Build practical skills, earn industry-recognized credentials, and accelerate your career in the evolving tech landscape. 

In this representation, the stack is implemented as an array, with the top of the stack being managed by an index variable.

Stack in C

Here’s the basic structure:

#define MAX 100  // Maximum stack size
int stack[MAX];  // Stack array
int top = -1;    // Initialize top of stack as -1
Alternatively, you can use a linked list to represent a stack. In this case, each stack element is stored in a node, with each node pointing to the next one. 
struct Node {
    int data;
    struct Node* next;
};

struct Node* top = NULL;

Both approaches are effective, but using a linked list is more flexible as it avoids the need to predefine a size.

Also Read: What are Data Structures in C & How to Use Them?

With the stack structure in place, let’s now explore the key operations that power stack functionality.

Stack Operations in C

Here’s a quick look at the basic operations performed on a stack:

Operation

Description

Time Complexity

Space Complexity

push()

Inserts an element at the top of the stack.

O(1)

O(1)

pop()

Removes the top element from the stack.

O(1)

O(1)

top()

Returns the top element without removing it.

O(1)

O(1)

isEmpty()

Checks if the stack is empty.

O(1)

O(1)

isFull()

Check if the stack is full.

O(1)

O(1)

push()

The push() operation adds an element to the top of the stack. It first creates a new node and then sets the new node’s pointer to the current top. The top pointer is updated to the new node, effectively making it the new top of the stack.

Algorithm for push():

  1. Create a new node.
  2. Set the node’s data to the value to be added.
  3. Link the node to the current top node.
  4. Update the top pointer to point to the new node.

pusp operation in stack

pop()

The pop() operation removes the top element from the stack. It first checks if the stack is empty. If not, the top element is removed, and the top pointer is updated to the next node in the stack.

Algorithm for pop():

  1. Check if the stack is empty (top == NULL).
  2. If empty, return an error message or a specific value (like -1).
  3. Otherwise, temporarily store the top node.
  4. Set the top pointer to the next node in the stack.
  5. Free the memory of the old top node.

pop operation in stack

top()

The top() operation retrieves the top element without removing it. It simply returns the value of the top element without modifying the stack.

Algorithm for top():

  1. Check if the stack is empty (top == NULL).
  2. If empty, return an error message or a specific value.
  3. Otherwise, return the value of the top node.

top peep operation in stack

isEmpty()

The isEmpty() operation checks if the stack is empty. It returns true if the stack is empty (i.e., the top pointer is NULL), and false otherwise.

Algorithm for isEmpty():

  1. Check if the top pointer is NULL.
  2. If NULL, return true (stack is empty).
  3. Otherwise, return false.

isempty operation in stack

isFull()

The isFull() operation checks if the stack is full. This operation isn't always necessary for a dynamic stack (implemented with a linked list) because the stack can grow as needed. For a static stack (e.g., using an array), it checks if the stack has reached its maximum capacity.

Algorithm for isFull():

  1. For dynamic stacks, always return false as the stack can grow.
  2. For static stacks, check if the size has reached the maximum limit.
  3. Return true if the stack is full; otherwise, return false.

ispop operation in stack

Also Read: Types of Operators in C: Roles, Usage & Best Practices 2025

On that note, let's look at the types of stacks and their specific applications.

Types of Stacks in C

In C programming, stacks can be classified into different types based on their implementation. The two main types of stacks are Static Stacks and Dynamic Stacks.

Understanding these will help you choose the right one for your application, especially when dealing with stack operations in C.

1. Static Stack

A static stack is implemented using arrays. The stack size is predefined, meaning it has a fixed size at the time of creation. This makes the static stack simple to implement and efficient for small applications where the size of the stack is predictable.

However, one limitation is that the size cannot be changed dynamically.

Example:

int top = -1;    #define MAX 100  // Set stack size
int stack[MAX];  // Array for stack
// Initialize top
  • Pros: Simple to implement, fast for small fixed-size stacks.
  • Cons: Limited size, memory is wasted if the stack size is not fully utilized.

2. Dynamic Stack

A dynamic stack is implemented using linked lists. Unlike the static stack, the size of the stack is not predefined. The stack grows and shrinks dynamically as elements are added or removed, making it more flexible than a static stack.

It avoids memory wastage since it only uses memory as needed.

Example:

struct Node {
    int data;
    struct Node* next;
};
struct Node* top = NULL;
  • Pros: Flexible size, avoids memory wastage, ideal for larger or unpredictable data.
  • Cons: More complex to implement, slower compared to static stacks due to pointer manipulation.

Here’s the list of a few other types of stacks:

3. Circular Stack

A circular stack wraps the end of the stack to the beginning, making better use of memory, especially in applications with fixed memory limits. Ideal for cases where stack overflow could occur in a linear stack, as it reuses the memory space.

Example:

struct Node {
    int data;
    struct Node* next;
};
  • Pros: Efficient memory use, no wasted space, reusable space, ideal for buffer-like use cases.
  • Cons: More complex implementation, can lead to confusion if not properly managed.

4. Double-Ended Stack (Deque)

A double-ended stack (deque) allows inserting and removing elements from both ends, making it a versatile data structure. It's commonly used when you need efficient access to both ends of the stack.

Example:

struct Node {
    int data;
    struct Node* next;
    struct Node* prev;
};
  • Pros: Fast insertion/removal from both ends, useful for scheduling or multi-threading tasks.
  • Cons: More memory overhead due to extra pointers, complex to implement and manage.

5. Multi-stack Implementation

A multi-stack implementation uses one array or linked list to manage multiple stacks. This method is useful in systems where different tasks need isolated memory spaces, such as in function calls or memory management systems.

Example:

int stack[MAX_SIZE];
int top[NUM_STACKS];
  • Pros: Efficient memory use when managing multiple tasks, allows multiple independent stacks in one structure.
  • Cons: Complexity increases when resizing or managing individual stacks, harder to implement, especially when resizing stacks dynamically.

6. Persistent Stack (Undo Stack)

A persistent stack preserves the history of its operations, enabling users to access previous states. This is perfect for applications like text editors, where users can undo actions and revert to previous versions of data.

Example:

struct Node {
    char action[100];
    struct Node* next;
};
  • Pros: Allows users to revert to previous states (ideal for undo operations) and maintains a history of actions for recovery.
  • Cons: Consumes more memory due to stored history, potentially slower performance due to maintaining previous states.

Why Choose the Right Stack?

The type of stack you choose affects your program's performance, memory usage, and complexity.

For example, a static stack is faster but has a fixed size, whereas a dynamic stack offers flexibility but may incur extra memory overhead. A circular stack can be more efficient when memory is reused, and a double-ended stack can optimize tasks that require access from both ends.

Understanding the types of stacks and their use cases can help you make better decisions and build more optimized solutions when performing stack operations in C.

Implementation of Stack: Browser History (Undo Functionality)

A real-life example of a stack is the browser history. When you visit websites, your browser stores the pages in a stack. The most recent page is always on top. If you press the "Back" button, the top page is popped off the stack, and the browser takes you to the previous page.

For this example, we will implement a simple stack that mimics this functionality with basic stack operations like push(), pop(), top(), isEmpty(), and isFull().

Let’s look at the algorithm:

  1. Initialize an empty stack: Create a stack that holds the browser pages as strings.
  2. Push Operation: Add a new page to the stack whenever you visit a new website.
  3. Pop Operation: Remove the top page when you press the back button to go to the previous website.
  4. Top Operation: Peek at the current top of the stack (current webpage).
  5. isEmpty: Check if there are no pages in the stack (empty history).
  6. isFull: This operation won't be used here since we are using dynamic memory allocation.

Let’s see how the code works out:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Define a node structure for the stack
struct Node {
    char url[100];     // Holds the website address
    struct Node* next; // Points to the next node in the stack
};
// Define the top of the stack (initially NULL)
struct Node* top = NULL;
// Push operation to insert a page (URL) at the top of the stack
void push(char url[]) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node)); // Allocate memory for a new node
    if (newNode == NULL) {
        printf("Memory overflow\n");
        return;
    }
    strcpy(newNode->url, url);  // Copy the URL into the new node's data field
    newNode->next = top;        // Link the new node to the current top node
    top = newNode;              // Move the top pointer to the new node
    printf("Visited: %s\n", url);  // Print the visited page URL
}
// Pop operation to remove the top page from the stack (back functionality)
void pop() {
    if (top == NULL) {  // Check if the stack is empty (no pages to go back to)
        printf("No history to go back\n");
        return;
    }
    struct Node* temp = top;  // Temporarily store the top node
    printf("Going back to: %s\n", temp->url);  // Print the page we are going back to
    top = top->next;  // Move the top pointer to the next node
    free(temp);       // Free the memory of the old top node
}
// Top operation to view the current page (without popping it)
void topPage() {
    if (top == NULL) {
        printf("No page in history\n");
        return;
    }
    printf("Currently on: %s\n", top->url);  // Print the current top page URL
}
// Check if the stack is empty
int isEmpty() {
    return top == NULL;
}
// Main function to simulate stack operations (browser history)
int main() {
    push("www.google.com");  // Visit Google
    push("www.youtube.com"); // Visit YouTube
    push("www.stackoverflow.com"); // Visit StackOverflow
    topPage();  // Check the current page
    pop();  // Go back to previous page
    pop();  // Go back to previous page
    topPage();  // Check the current page after going back
    return 0;
}

Output:

Visited: www.google.com

Visited: www.youtube.com

Visited: www.stackoverflow.com

Currently on: www.stackoverflow.com

Going back to: www.stackoverflow.com

Going back to: www.youtube.com

Currently on: www.google.com

Explanation:

  1. Push Operation (Visiting a Website):
    • The URL is pushed onto the stack every time a user visits a page. The top pointer is updated to point to the most recent page.
  2. Pop Operation (Going Back):
    • When the "Back" button is pressed, the top URL is removed from the stack. The top pointer then moves to the previous page in history, effectively going back in the browser.
  3. Top Operation (Current Page):
    • This operation allows us to view the page that was visited most recently (the one at the top of the stack).
  4. isEmpty Operation (Checking if Stack is Empty):
    • This checks whether there is any page in history. If no pages are left, it prints "No history to go back."

In this example, we simulate the browser's "Back" functionality using stack operations in C. The stack holds a history of pages, and you can easily go back through the pages as needed using the pop() operation.

MCQs on Stack in C

1. What is the condition to check for stack overflow in an array-based stack?

a) top < 0

b) top == 0

c) top == MAX - 1

d) top != -1

2. What does the pop() operation do in a stack?

a) Removes top element

b) Adds element to the bottom

c) Sorts the stack

d) Returns the middle element

3. What is the time complexity of push() and pop() in a stack using an array?

a) O(n)

b) O(log n)

c) O(1)

d) O(n²)

4. In an array-based stack, which variable always tracks the topmost element?

a) size

b) count

c) head

d) top

5. What will happen if you pop from an empty stack?

a) Returns garbage value

b) Stack resets

c) Underflow error

d) Overflow error

6. Which of the following correctly implements the push() operation?

a) stack[++top] = value;

b) stack[top++] = value;

c) stack[top] = value; top++;

d) All of the above can work

7. Which of the following is not a valid application of stacks?

a) Expression evaluation

b) Backtracking

c) Page navigation in browser

d) Level-order traversal of a tree

8. What is the output of this stack-based code snippet?

int stack[3], top = -1;
stack[++top] = 10;
stack[++top] = 20;
stack[++top] = 30;
printf("%d", stack[top--]);

a) 30

b) 20

c) 10

d) Stack Overflow

9. A student implements a stack using array, but data overwrites on push(). What is likely missing?

a) MAX check for overflow

b) Memory allocation

c) Decrement of `top` in `pop()`

d) Stack header file

10. You’re designing a stack-based undo feature. Why is stack preferred here?

a) LIFO matches last action undo

b) Easy to loop through

c) Fast insertions

d) It sorts operations

11. You use `top = -1` to initialize your stack. Why?

a) Indexing from 0

b) To avoid garbage values

c) It simplifies boundary checks

d) All of the above

Conclusion 

In C programming, a stack is a versatile data structure that allows efficient data management through the Last-In, First-Out (LIFO) principle. Understanding stack operations in C, such as push, pop, top, isEmpty, and isFull, is essential for implementing algorithms, managing recursion, and handling real-world scenarios like browser history or undo functionalities.  

Learning these operations ensures optimized performance and memory usage. By practicing the implementation of a stack in C, you develop the skills to manage sequential data effectively and solve complex programming problems efficiently. 

How Can upGrad Help You Master Stack in C?

upGrad’s courses offer a comprehensive, hands-on approach to mastering C programming, including concepts like stacks, recursion, and data structures. Whether you’re learning how stacks operate or optimizing your stack-based algorithms, upGrad’s expert-led courses will guide you step-by-step through key C programming concepts.

Through our interactive courses, you'll gain practical experience working with stacks, from implementing basic operations to tackling more advanced applications in system-level programming and competitive coding.

Check out upGrad’s programs to advance your knowledge:

You can also get personalized career counseling with upGrad to guide your career path, or visit your nearest upGrad center and start hands-on training today!

Similar Reads:

Explore C Tutorials: From Beginner Concepts to Advanced Techniques
Array in C: Introduction, Declaration, Initialisation and More
Exploring Array of Pointers in C: A Beginner's Guide
What is C Function Call Stack: A Complete Tutorial
Binary Search in C
Constant Pointer in C: The Fundamentals and Best Practices
Find Out About Data Structures in C and How to Use Them?

FAQs

1. What is the main advantage of using a stack in C program over other data structures? 

A stack in C program follows the LIFO (Last-In, First-Out) principle, providing efficient access to the most recent element. This makes it ideal for use cases like recursion, undo functionalities, expression evaluation, and tracking program execution states. Its simplicity and predictable behavior make it a preferred choice for certain algorithmic operations. 

2. How do stack operations in C compare in terms of efficiency? 

Stack operations like push() and pop() in C typically operate in constant time O(1). This makes them highly efficient for managing data in a LIFO structure. The top() or peek() operation is also O(1), allowing quick access to the most recent element without removing it. Efficiency remains consistent regardless of stack size. 

3. Can stack operations in C be implemented without dynamic memory allocation? 

Yes, stack operations in C can be implemented statically using arrays. A fixed-size array provides predictable memory usage and simple implementation. However, dynamic memory allocation using linked lists offers flexibility and scalability, as the stack can grow or shrink as needed without predefined limits. Each approach has its trade-offs between simplicity and adaptability. 

4. What are some real-life scenarios where stack operations in C are used? 

Stacks are widely used in real-life programming scenarios. Common examples include managing browser history, implementing undo features in text editors, evaluating mathematical expressions, handling recursive function calls, and parsing syntax in compilers. Their LIFO behavior allows applications to easily retrieve the most recent action or element first. 

5. How does memory management work with stack operations in C? 

In dynamic stack implementations using linked lists, memory is allocated for each node when added (push()) and freed when removed (pop()). This ensures efficient memory usage, preventing wastage. For static stacks (arrays), memory is preallocated, which can lead to unused space if the stack is not full, but avoids runtime memory management overhead. 

6. What happens if we try to pop from an empty stack in C? 

Popping from an empty stack results in a stack underflow error. This can cause program crashes or unexpected behavior if not handled. To prevent this, always check whether the stack is empty using isEmpty() before performing a pop operation. Proper error handling ensures the program remains safe and predictable. 

7. What is the difference between stack overflow and stack underflow in C? 

Stack overflow occurs when attempting to push an element onto a full stack, exceeding its capacity. Stack underflow happens when trying to pop an element from an empty stack. Both conditions can cause errors, and it’s important to implement proper checks to prevent memory corruption or crashes. 

8. What are the limitations of using an array to implement a stack in C? 

Using arrays for stacks requires a fixed size defined at compile time. This limits flexibility and can lead to memory wastage if the array is larger than needed or stack overflow if the array is too small. Dynamic implementations with linked lists are more flexible but slightly more complex to manage. 

9. How does the top() operation in stack operations in C work? 

The top() operation, also called peek(), returns the value at the top of the stack without removing it. This allows programs to view the most recent element efficiently. It’s an O(1) operation and is particularly useful for decision-making in algorithms where the last inserted element’s value is required without modifying the stack. 

10. Can stack operations in C be implemented recursively? 

Yes, stack operations can be implemented using recursion. For example, recursive function calls naturally use the program’s call stack. Custom recursive stack functions can also simulate push and pop behaviors. However, recursive stack implementations need careful handling of stack overflow and memory limits, especially for deep recursion. 

11. Why is it important to check for stack overflow in stack operations in C? 

Checking for stack overflow prevents attempts to push onto a full stack. Without this check, memory corruption, crashes, or unexpected behavior may occur. In static stacks, this involves comparing the current size with the maximum limit. In dynamic stacks, proper memory allocation checks prevent runtime errors and maintain program stability. 

12. What is the difference between static and dynamic stacks in C? 

A static stack uses a fixed-size array and cannot grow beyond its predefined size. It’s simple and fast but lacks flexibility. A dynamic stack uses a linked list, allowing flexible growth and shrinkage as needed. Dynamic stacks avoid memory wastage but require pointer management, making implementation slightly more complex. 

13. How can a stack in C be used for expression evaluation? 

Stacks can evaluate expressions like postfix, prefix, or infix notations. Operands are pushed onto the stack, and operators pop operands to perform calculations. This LIFO behavior ensures the correct order of operations is maintained, simplifying expression evaluation in compilers and calculators. 

14. What is a circular stack and when is it used? 

A circular stack connects the end of the stack to the beginning, effectively reusing memory space. It’s particularly useful for fixed-size buffers or applications where stack overflow must be minimized, such as embedded systems or real-time task scheduling. It optimizes memory but adds implementation complexity. 

15. How does a double-ended stack (deque) differ from a standard stack? 

A double-ended stack, or deque, allows insertion and removal of elements from both ends. This provides more flexibility than a standard LIFO stack. Deques are used in scheduling, multi-threaded task management, or any scenario requiring efficient access to both the newest and oldest elements. 

16. Can multiple stacks share the same memory in C? 

Yes, multi-stack implementations allow multiple stacks to share the same array or linked list. This is useful for memory optimization in systems with limited space. Each stack maintains its own top pointer or index. However, managing resizing and ensuring no overlap adds complexity to the implementation. 

17. What is a persistent stack and where is it used? 

A persistent stack preserves previous states, enabling undo operations or historical data access. Each push or pop operation creates a new state while maintaining prior states. It’s commonly used in text editors, version control systems, and applications where history tracking is critical. 

18. How is stack implemented for browser history in C? 

Browser history is implemented as a dynamic stack. Each visited URL is pushed onto the stack. Pressing the back button triggers a pop operation, removing the top URL and showing the previous one. top() allows viewing the current page. This simulates real-world undo and navigation functionalities efficiently. 

19. What precautions should be taken when implementing a stack in C? 

Always check for overflow and underflow conditions to prevent crashes. Choose the right stack type (static vs dynamic) based on memory and performance needs. Free dynamically allocated memory properly and avoid pointer errors. Ensure operations maintain LIFO behavior to preserve stack integrity. 

20. How do stack operations in C help in recursion management? 

Recursion inherently uses the call stack, which operates as a stack in C. Each function call is pushed onto the call stack, and when the function completes, it’s popped. Understanding stack operations helps manage recursion depth, prevent stack overflow, and implement custom recursive algorithms efficiently. 

image

Take a Free C Programming Quiz

Answer quick questions and assess your C programming knowledge

right-top-arrow
image
Pavan Vadapalli

Author|900 articles published

Pavan Vadapalli is the Director of Engineering , bringing over 18 years of experience in software engineering, technology leadership, and startup innovation. Holding a B.Tech and an MBA from the India....

image
Join 10M+ Learners & Transform Your Career
Learn on a personalised AI-powered platform that offers best-in-class content, live sessions & mentorship from leading industry experts.
advertise-arrow

Free Courses

Start Learning For Free

Explore Our Free Software Tutorials and Elevate your Career.

upGrad Learner Support

Talk to our experts. We are available 7 days a week, 9 AM to 12 AM (midnight)

text

Indian Nationals

text

Foreign Nationals

Disclaimer

  1. The above statistics depend on various factors and individual results may vary. Past performance is no guarantee of future results.

  2. The student assumes full responsibility for all expenses associated with visas, travel, & related costs. upGrad does not .