15Pointers and Memory
Cryo is a systems language. There is no garbage collector. Memory is managed manually through explicit allocation and deallocation, or, preferably, through RAII patterns: a type that owns memory implements Drop, and its destructor releases what its constructor acquired.
15.1 Address-of and Dereference
The & operator takes the address of a value. The * operator follows a pointer to its target.
mut x: int = 42;
const ptr: int* = &x; // ptr holds the address of x
const val: int = *ptr; // val is 42
Pointer indexing is supported: ptr[0] is *ptr, and ptr[n] accesses the n-th element from the pointer's base.
15.2 Heap Allocation
Low level (malloc / free) for raw byte buffers and FFI-shaped allocations:
const buf: u8* = malloc(1024) as u8*;
buf[0] = 0xFF;
free(buf);
Class instances (new / delete):
const p: Person* = new Person("Alice", 30);
delete p;
Array allocation (new T[n]):
const arr: int* = new int[100];
new T[n] allocates room for n contiguous T and yields a T*. The memory is uninitialized and no constructors run - it is the typed equivalent of malloc(n * sizeof(T)). Free it with free(arr as void*). For constructed, growable, bounds-checked storage prefer Array<T>.
Higher level (Box<T> and the collections). Prefer Box<T> over raw malloc for owning a single heap value, and prefer Array<T> / String / HashMap<K, V> over manual allocation for collections. They handle reservation, growth, and cleanup, and they implement Drop.
15.3 Null
null is the null pointer literal, valid in any pointer context. The primitive string is pointer-shaped (a NUL-terminated u8*), so it counts as a pointer context: null assigns to, initializes, returns as, and compares with a string without a cast.
const p: int* = null;
if (p == null) { println("null"); }
const s: string = null; // string is pointer-shaped
if (s == null) { println("no name"); }
Dereferencing a null pointer is undefined behaviour. For "may be absent" semantics on a value, use Option<T> rather than a nullable pointer; the compiler then forces you to handle the absent case at every use.
15.4 NonNull
core::ptr::NonNull<T> is a thin wrapper around T* that statically guarantees non-nullness. Containers and smart pointers in the standard library use NonNull<T> internally so they never have to defensively null-check.
import core::ptr::NonNull;
const non_null: NonNull<u8> = NonNull::new(buf).unwrap();