Arrays & Slices
Sequence data structures
Introduction
In this lesson, you'll learn about arrays & slices in Go. Coming from C, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.
In C, you're familiar with sequence data structures.
Go has its own approach to sequence data structures, which we'll explore step by step.
The Go Way
Let's see how Go handles this concept. Here's a typical example:
package main
import "fmt"
func main() {
// Fixed array (rarely used directly)
var nums [5]int = [5]int{1, 2, 3, 4, 5}
// Slice — dynamic, the idiomatic way
s := []int{1, 2, 3, 4, 5}
s = append(s, 6) // grow
s2 := append(s, 7, 8, 9) // chain
sub := s[1:4] // slice of slice [2,3,4]
fmt.Println(len(s), cap(s))
// make for pre-allocated slices
big := make([]int, 10, 100) // len=10, cap=100
// Pass slice — no need for length param
printSlice(s)
}
func printSlice(s []int) {
for _, v := range s {
fmt.Println(v)
}
}Comparing to C
Here's how you might have written similar code in C:
#include <stdio.h>
#include <stdlib.h>
/* Fixed-size array */
int nums[5] = {1, 2, 3, 4, 5};
int n = sizeof(nums)/sizeof(nums[0]);
/* Dynamic array */
int *dyn = malloc(5 * sizeof(int));
dyn[0] = 10;
/* ... fill ... */
dyn = realloc(dyn, 10 * sizeof(int));
free(dyn);
/* Pass array to function — pointer + length */
void printArr(int *arr, int len) {
for (int i = 0; i < len; i++)
printf("%d ", arr[i]);
printf("\n");
}You may be used to different syntax or behavior.
Go slices are dynamic and garbage-collected; C dynamic arrays need malloc/free
You may be used to different syntax or behavior.
Go slices carry their length — no need to pass length as separate param
You may be used to different syntax or behavior.
append() in Go replaces realloc(); no manual size tracking
You may be used to different syntax or behavior.
Go's range replaces C's for(i=0; i<n; i++) pattern
Step-by-Step Breakdown
1. Slices vs Arrays
Go arrays are fixed-size and rarely used directly. Slices are the idiomatic Go collection — dynamic, length-aware, and garbage-collected.
int arr[5] = {1, 2, 3, 4, 5};s := []int{1, 2, 3, 4, 5} // slice, not array2. append vs realloc
Go's append automatically grows the backing array when needed, replacing the error-prone realloc pattern.
dyn = realloc(dyn, new_size * sizeof(int));s = append(s, newElement)3. Slices as Parameters
Go slices include their length, so you never need a separate length parameter. The called function can use len() directly.
void printArr(int *arr, int len) { ... }func printSlice(s []int) {
fmt.Println(len(s)) // length built-in
}Common Mistakes
When coming from C, developers often make these mistakes:
- Go slices are dynamic and garbage-collected; C dynamic arrays need malloc/free
- Go slices carry their length — no need to pass length as separate param
- append() in Go replaces realloc(); no manual size tracking
Key Takeaways
- Go slices replace C's manual dynamic arrays
- append() replaces malloc/realloc
- Slices carry their length — no extra parameter needed
- range replaces C's index-based for loops