We want:
- memory that sticks around when exiting functions
- too big for stack
- but need it dynamic
- not .text as not read/write
- cannot go into .data, .bss as size is not known pre-execution.
→ For this we need dynamically allocated memory viamalloc(to allocate a memory region on the heap).
get’s freed on program end by OS, or deallocated manually / by GC.
Memory Management in C
typedef
typedef unsigned long size_t;
void *malloc(size_t sz);
returns a pointer to a block of memory at least as long as size bytes.
- returns NULL if it didn’t work
DO NOT Assume that the memory is 0 → uninitialised
Note: Pages vs. Malloc’ed memory
Note that the program mmaps an entire page (which the OS hands zeroed). Malloc then internally manages those pages.
- thus we only get non-zero malloced memory if that same page had something at those bytes before.
→ malloc can reuse freed memory
Calloc: Note there is also calloc, which allocates a zeroed block of memory. You hand it a number of elements and an element size.
- slightly slower but less memory prone.
Realloc: we can also shrink / extend a block of memory realloc(void *ptr, size_t size)
- allocations have a fixed size
- always use the new address returned!
- might copy the entire block to a new location!
- contract does not guarantee anything (might be copied, extend in place, etc…)
free
Releases memory at the pointer.
- must point to first byte at
malloc’ed memory - after freeing → this memory region can be reused
Note: good practice to NULL after freeing
- CANNOT free memory twice
Note: we don’t need to specify a size → knows because malloc stores stuff
size_t and ptrdiff_t
size_t: (return type of sizeof)
- unsigned inter of some size
- guaranteed to be large enough to hold the size of the largest possible array in memory
- can be used to store pointer
ptrdiff_t: a signed integer of some size, result of subtracting two pointers
- used for array loops, size calculations
Heap
Malloc manages the heap space. It can run out (through memory leaks for ex).
GCed language can still have memory leaks → for example through cycles (but much less likely).
Structures and Unions
structs
p->x is short for (*p).x. We cannot just use .attr for a pointer to the struct.
Structs can be copied by assignment person1 = person2 → automatically copies for you.
- this means you can pass a stuct by value!
- This also means you can return a struct (not a pointer to a struct, but actually a struct).
void broken(struct point p) {
p.x *= 2;
}
void works(strruct point *p) {
p->x *= 2;
}Can contain itself / pointer to itself → for trees for example
The struct name person for example → is a tag! It’s not the same namespace as a type!
Union
Union like a struct, but holds only one of a set of alternative values
- accesses like a struct
- no checking on which value
union u {
int ival;
float fval;
char *sval;
};
union u my_uval; // can be any of int, float, char*→ how do get which size this is?
typedef
typedef introduces a new type definition
- new name for a type
- can be used wherever original type could be
→ nice synonym / alias mechanism (can be recursively used)
typedef struct skbuf skbuf_t → instead of writing “struct skbuf” we can just write skbuf_t s.
- some people think this is good idea
usingtypedeffor struct stuff - can even inline the struct definition in a typedef
- or even recursive struct in there
Namespaces
- Label names
- see
goto
- see
- Tags
- one namespace for all structs, unions, enums
- Member Names
- one namespace for all structs, unions, enums
- Everything else (mostly)
- including typedef