Regular Pointers
Pointers in Go are specialized varible types that store the memory address of another variable. While not as frequently used as in C or C++, pointers remain essential for modifying variables within functions, avoiding expensive large object copies, and implementing data structures like linked lists and trees.
Fundamental Concepts
- Memory Address: Every variable occupies memory space with a unique address. A pointer variable stores this address.
- Dereferencing: Accessing the value at the address a pointer holds is called dereferencing.
Declaring Pointers
Pointer declaration uses the * operator before the type:
var count *int
Here, count is a pointer to an int value.
Initializing Pointers
Pointers must be initialized before use. The & operator retrieves a variable's address:
number := 15
address := &number
In this example, address holds the memory location of variable.
Dereferencing Pointers
The * operator dereferences a pointer to access or modify its underlying value:
*address = 25
This changes number to 25.
Pointers in Functions
Passing pointers to functions enables modification of external variables:
func updateValue(ptr *int) {
*ptr = 45
}
func main() {
number := 15
updateValue(&number)
fmt.Println(number)
}
The updateValue function modifies number through its pointer parameter.
Nil Pointers
Uninitialized pointers default to nil, indicating they reference no address:
var count *int
if count == nil {
fmt.Println("Pointer is uninitialized")
}
Pointers and Structs
Pointers work naturally with structs for creating and modifying struct instances:
type Employee struct {
Name string
Salary int
}
func main() {
staff := &Employee{Name: "Bob", Salary: 5000}
staff.Salary = 5500
}
Pointer Arrays vs Array Pointers
- Pointer Array: An array containing pointer elements
var ptrSlice [4]*string
- Array Pointer: A pointer pointing to an entire array
var items [4]string
var arrayRef *[4]string = &items
Pointers to Pointers
Go supports multiple levels of indirection:
num := 200
ptr := &num
doubleRef := &ptr
Here, doubleRef points to ptr, which points to num.
Important Considerations
- Go prohibits pointer arithmetic—you cannot add or subtract from pointers.
- The garbage collector automatically manages memory, eliminating the need for manual deallocation.
unsafe.Pointer
The unsafe.Pointer type in Go can reference any type's value. The unsafe package bypasses Go's type system, enabling operations like type conversion between pointers and calculating actual memory sizes of objects.
Type Conversion
unsafe.Pointer facilitates conversion between arbitrary pointer types:
package main
import (
"fmt"
"unsafe"
)
func main() {
val := 36
intRef := &val
genericPtr := unsafe.Pointer(intRef)
rawAddr := uintptr(genericPtr)
genericPtr = unsafe.Pointer(rawAddr)
converted := (*int)(genericPtr)
*converted = 72
fmt.Println(val)
}
Accessing Arbitrary Memory Addresses
unsafe.Pointer can access any memory location, bypassing Go's type safety:
target := unsafe.Pointer(uintptr(0xDEADBEEF))
This attempts to access a specific memory address—extremely dangerous and likely to cause undefined behavior or crashes.
Calculating Struct Sizes
unsafe.Sizeof returns byte size of values, often used with unsafe.Pointer for struct analysis:
type Record struct {
ID int
Data string
}
entry := Record{ID: 1, Data: "sample"}
size := unsafe.Sizeof(entry)
fmt.Println(size)
Pointer Arithmetic with uintptr
Go forbids arithmetic on unsafe.Pointer. Convert to uintptr, perform calculations, then convert back:
data := Record{ID: 1, Data: "sample"}
basePtr := unsafe.Pointer(&data)
addr := uintptr(basePtr)
fieldPtr := unsafe.Pointer(addr + unsafe.Offsetof(data.Data))
Usage Guidelines
- The
unsafepackage bypasses memory safety guarantees—errors can cause crashes or security vulnerabilities. - Limit
unsafeusage to essential scenarios and ensure operation safety. unsafepackage internals may change between Go versions.
uintptr Type
uintptr is a unsigned integer type in the unsafe package large enough to hold any pointer's bit pattern (memory address). It's designed for low-level programming involving OS interfaces and memory operations.
Key Characteristics
uintptrstores the complete bit pattern of any pointer type.- Enables bidirectional conversion between pointers and integers.
- Supports pointer arithmetic while bypassing Go's safety checks.
Practical Example
package main
import (
"fmt"
"unsafe"
)
func main() {
val := 128
ptr := &val
addrValue := uintptr(unsafe.Pointer(ptr))
newLocation := unsafe.Pointer(addrValue + unsafe.Sizeof(val))
typedPtr := (*int)(newLocation)
*typedPtr = 256
fmt.Println(val)
}
Critical Warnings
uintptrusage demands extreme caution—improper handling causes memory corruption, out-of-bounds access, and crashes.- Never store
uintptrvalues persistently—they become invalid during garbage collection. - Direct
uintptrusage is rare; reserve it for OS-level or hardware interaction code.
Comparing the Three Pointer Types
Go provides three distinct pointer-related concepts, each serving different purposes in memory operations and type conversion.
Standard Pointers (*Type)
- Definition: Variables storing another variable's memory address.
- Purpose: Reference and modify values, pass addresses to functions for in-place updates.
- Type Safety: Fully type-safe—can only reference specific types.
- Example:
val := 10
ptr := &val
*ptr = 50
unsafe.Pointer
- Definition: A special
unsafepackage type that can reference any type. - Purpose: Type conversion between pointers, low-level memory operations.
- Type Safety: Not inherently safe—it can reference any type but requires accompanying safe pointer usage.
- Example:
val := 10
ptr := unsafe.Pointer(&val)
uintptr
- Definition: An unsigned integer type in
unsafepackage large enough for any pointer's bit pattern. - Purpose: Pointer arithmetic, converting pointers to integers for low-level operations.
- Type Safety: Unsafe—stores arbitrary bit patterns and enables arithmetic that bypasses memory guarantees.
- Example:
val := 10
ptr := uintptr(unsafe.Pointer(&val))
Comparative Summary
| Aspect | *Type |
unsafe.Pointer |
uintptr |
|---|---|---|---|
| Type Safety | High | Low | None |
| Primary Use | Variable references | Type conversion | Arithmetic operations |
| Garbage Collection | Safe | Manual responsibility | Manual responsibility |
| Arithmetic Support | No | No | Yes |
Standard pointers provide type-safe variable access for everyday programming. unsafe.Pointer and uintptr enable low-level operations with significant power but require meticulous handling to maintain program integrity.