Comparing Array-Based Stacks in C and Go

I’ll be comparing stack-based arrays in C and Go. There are many ways to implement a stack, but the aim here is for simplicity.

Stacks in C


Non-Functionial Approach

Filling a stack with integers 1 through 10.

#include <stdio.h>

int main()
{
        int stack[10];
        int top = -1; 

        int i = 1;
        while(top+1 < 10) 
        {   
                stack[++top] = i;
                i++;
        }   

	// print 
        for(int i=0; i < 10; i++) printf("STACK[%d]=%d\n",i,stack[i]); 


        return 0;
}

In need of a stack, this will do. The big deal here is stack[++top]=i which is our push functionality. Pop can be achieved similarly, and peek is stack[top].

Functional Approach

Things get more interesting with functions involved. The code is more resuable, unlike the code above which is more of a one-off.

#include <stdbool.h>
#include <stdio.h>

bool push(int arr[], int size, int *top, int element);

int main(){
        int stack[10];
        int top = -1; 

        int i = 0;
        while(push(stack, 10, &top, ++i)){}

	// print 
        for(int i=0; i < 10; i++) printf("STACK[%d]=%d\n",i,stack[i]); 

        return 0;
}

bool push(int arr[], int size, int *top, int element)
{
        if((*top)+1 == size) return false;
        arr[++(*top)] = element;

        return true;
}

Now the function will all the work in a while loop like while(push(stack, 10, &top, ++i)){}.

Stacks in Go


Without Functions

Nearly identical to C:

package main

import "fmt"

func main(){
        var stack [10]int                         
        top := -1 

        i := 1
        for top+1 < 10 {
                top++
                stack[top] = i
                i++
        }                     

	// print
        for i := range stack {fmt.Printf("STACK[%d]=%d\n",i,stack[i])}
}

There are some syntax differences such as Go’s lack of a prefix increment operator which would make a terse statement like stack[++top] = i; possible in C.

It’s also worth noting that the array declared as var stack [10]int is automatically zeroed-out.

With Functions

package main

import "fmt"

func push(arr []int, top *int, element int) bool {
        if *top + 1 == len(arr) {return false}
        *top++
        arr[*top] = element

        return true
}

func main(){
        var stack [10]int
        top := -1

        i := 1
        for push(stack[:],&top,i) != false {i++}

        // print
        for i := range stack {fmt.Printf("STACK[%d]=%d\n",i,stack[i])}

}

We can put what is essentially a while loop to work again but this time, in Go syntax as for push(stack[:],&top,i) != false {i++}. We cannot increment our i variable here in our function call like we can in C unfortunately, so the body of our loop gets a single line.

There is a greater difference here, however. When passing the array to the push function, it must be passed as a slice (a dynamic subarray pointing to the actual array). The expression stack[:] creates this slice with the endpoints omitted.

To not pass in a slice, the function signature would look like func push(arr [10]int, top *int, element int) bool, where the size of the array must be explicitly stated and therefore only size 10 arrays would be allowed in this function.

Go’s Built-In Dynamic Arrays

Go will let you append to a slice with a statement like stack = append(stack, i), which would manage the top of the stack for you, the catch being that this can only be done with slices and not statically sized arrays.