Pointer Basics in Go
Part of the Object Oriented Programming section of Coddy's GO journey — lesson 19 of 107.
A pointer is a variable that stores the memory address of another variable. Instead of holding a value directly, it holds the location where that value lives in memory. Pointers are fundamental to Go and essential for efficient data manipulation.
To create a pointer, use the & operator to get a variable's address, and the * operator to declare a pointer type or access the value at that address.
x := 42
p := &x // p holds the memory address of x
fmt.Println(p) // 0xc000018030 (memory address)
fmt.Println(*p) // 42 (value at that address)The & operator means "address of" and returns a pointer. The * operator, when used on a pointer, means "value at" and is called dereferencing. You can also modify the original value through the pointer.
x := 10
p := &x
*p = 25 // change value through pointer
fmt.Println(x) // 25 (original variable changed)The pointer type is written as *T where T is the type being pointed to. A pointer to an int has type *int.
var p *int // declares a pointer to int
x := 100
p = &x // p now points to xThe zero value of a pointer is nil, meaning it points to nothing. Attempting to dereference a nil pointer causes a runtime panic, so always ensure pointers are initialized before use.
Challenge
EasyLet's build a simple value swapper that demonstrates the power of pointers to modify variables through their memory addresses.
You'll organize your code across two files:
swap.go: Create a function calledSwapValuesthat takes two*intpointers as parameters. This function should swap the values that these pointers point to—after calling it, each variable should hold the other's original value. The function doesn't return anything; it modifies the values directly through the pointers.main.go: Read two integers from input, store them in variables, then use yourSwapValuesfunction to exchange their values. Print both values before and after the swap to show the change.
The following inputs will be provided:
- Line 1: First integer
- Line 2: Second integer
Output format:
Before: a=[first] b=[second]
After: a=[first] b=[second]For example, given 10 and 25, your output should be:
Before: a=10 b=25
After: a=25 b=10Remember to use the & operator when passing your variables to the function, and the * operator inside the function to access and modify the actual values.
Cheat sheet
A pointer is a variable that stores the memory address of another variable. Use the & operator to get a variable's address, and the * operator to declare a pointer type or access the value at that address.
x := 42
p := &x // p holds the memory address of x
fmt.Println(p) // 0xc000018030 (memory address)
fmt.Println(*p) // 42 (value at that address)The & operator means "address of" and returns a pointer. The * operator, when used on a pointer, means "value at" and is called dereferencing.
You can modify the original value through the pointer:
x := 10
p := &x
*p = 25 // change value through pointer
fmt.Println(x) // 25 (original variable changed)The pointer type is written as *T where T is the type being pointed to:
var p *int // declares a pointer to int
x := 100
p = &x // p now points to xThe zero value of a pointer is nil. Attempting to dereference a nil pointer causes a runtime panic.
Try it yourself
package main
import "fmt"
func main() {
// Read two integers from input
var a, b int
fmt.Scanln(&a)
fmt.Scanln(&b)
// Print values before swap
fmt.Printf("Before: a=%d b=%d\n", a, b)
// TODO: Call SwapValues function with pointers to a and b
// Remember to use the & operator to pass addresses
// Print values after swap
fmt.Printf("After: a=%d b=%d\n", a, b)
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of Go OOP
External FilesGo Workspace & ModulesPackages & ImportsExported vs Unexported NamesIntroduction to OOP in GoStructs as ClassesDefining Methods on StructsPointer vs Value ReceiversStruct InitializationConstructor FunctionsRecap - Simple Calculator4Interfaces
Introduction to InterfacesImplicit ImplementationInterface as ContractEmpty Interface (any)Type AssertionType SwitchInterface CompositionStringer & Error InterfacesRecap - Shape Calculator7Encapsulation
Exported vs Unexported FieldsPackage-Level EncapsulationGetter & Setter MethodsInformation Hiding in GoRecap - Student Records10Generics (Go 1.18+)
Introduction to GenericsType ParametersType ConstraintsGeneric StructsGeneric Methods WorkaroundRecap - Generic Collection2Types & Structs Deep Dive
Basic & Composite TypesCustom Type DefinitionsStruct TagsAnonymous StructsNested StructsZero Values & DefaultsRecap - Contact Book5Composition Over Inheritance
Why Go Has No InheritanceStruct Embedding BasicsMethod PromotionEmbedding Multiple StructsEmbedding vs AggregationShadowing Embedded MethodsRecap - Employee Hierarchy8Error Handling & OOP
The error InterfaceCustom Error TypesError Wrapping (fmt.Errorf)Sentinel Errorserrors.Is() and errors.As()Panic, Defer, and RecoverRecap - File Parser3Pointers & Memory
Pointer Basics in GoPointers to StructsPass by Value vs ReferenceThe new() FunctionGarbage Collection in GoRecap - Linked List Builder6Polymorphism in Go
Polymorphism via InterfacesDuck Typing in GoInterface Satisfaction RulesPolymorphic CollectionsDependency InjectionRecap - Payment Processor9Concurrency & OOP
Goroutines BasicsChannels & CommunicationBuffered vs Unbuffered ChanSelect Statementsync.Mutex & sync.RWMutexsync.WaitGroupThread-Safe Struct DesignRecap - Worker Pool