|
|
|
Lecture 11 — memory and the heap
|
|
|
|
|
why dynamic allocation?
|
|
|
|
|
can you define a struct for a linked list of ints?
|
|
|
|
|
struct node { int data; struct node next; }
|
|
|
|
|
generates compiler error
|
|
|
|
|
struct node { int data; struct node *next; }
|
|
|
|
|
will compile, but how to we create the node next points to?
|
|
|
|
|
picture of memory
|
|
|
|
|
stack allocation
|
|
|
|
|
stores local variables
|
|
|
|
|
automatically allocated when a function is called
|
|
|
|
|
data must be a constant size
|
|
|
|
|
so compiler knows how much space to allocate
|
|
|
|
|
caveat: variable-length arrays added by C99
|
|
|
|
|
automatically deallocated when a function returns
|
|
|
|
|
heap allocation
|
|
|
|
|
manually allocated
|
|
|
|
|
arbitrary size
|
|
|
|
|
manually deallocated
|
|
|
|
|
void *malloc(size_t size)
|
|
|
|
|
size is the number of bytes to be allocated
|
|
|
|
|
size_t is an alias for an unsigned integer (compiler defined)
|
|
|
|
|
void* gets automatically promoted to the type of the left-hand side
|
|
|
|
|
char *s = malloc(10); // no need for a cast
|
|
|
|
|
but, not uncommon to include cast, especially since C++ requires it
|
|
|
|
|
char *s = (char*)malloc(10);
|
|
|
|
|
void* calloc (size_t num, size_t size);
|
|
|
|
|
takes the number of things and the size of each thing as separate parameters
|
|
|
|
|
initializes all the allocated memory with zeros
|
|
|
|
|
use sizeof to allocate memory for non-char types
|
|
|
|
|
int *number = malloc(sizeof(int));
|
|
|
|
|
int *numbers = malloc(length * sizeof(int));
|
|
|
|
|
better practice: int *numbers = malloc(length * sizeof(*numbers));
|
|
|
|
|
sizeof is its own special thing
|
|
|
|
|
can be applied to types or values
|
|
|
|
|
( ) optional, but useful for clarity
|
|
|
|
|
void free(void *ptr)
|
|
|
|
|
deallocate memory pointed to by ptr
|
|
|
|
|
standard library must remember how big the allocated memory is
|
|
|
|
|
more on this later — you will implement this in hw5!
|
|
|
|
|
freeing the same memory more than results in undefined behavior
|
|
|
|
|
malloc and free are in stdlib.h
|
|
|
|
|
examples
|
|
|
|
|
int main(int argc, char **argv) { // check number of args char * filename = malloc(strlen(argv[1]) + 1); // why the + 1? null terminator strncpy(filename, argv[1], strlen(argv[1]) + 1); // other operations free(filename); }
|
|
|
|
|
int main(int argc, char **argv) { // check number of args int n = atoi(argv[1]); int * nums = malloc(sizeof(*nums) * n); for(int i = 0; i < n; i++) { scanf(“%d”, nums + i); // could also do &nums[i] } // other operations free(nums); }
|
|
|
|
|
exercise: write a version of makepoint that allocates the new point on the heap
|
|
|
|
|
Point* makepoint(int x, int y) { Point *p = malloc(sizeof(*p)); p->x = x; p->y = y; return p; }
|
|
|
|
|
exercise: where is the memory leak?
|
|
|
|
|
int main() { char *s1 = malloc(10); char *s2 = malloc(10); s1 = s2; }
|
|
|
|
|
nothing points to the memory allocated to s1, so it can’t be freed
|
|
|
|
|
void f() { int *nums = malloc(10 * sizeof(*nums)); // do stuff with nums return; }
|
|
|
|
|
once f returns, nothing points to the memory allocated to nums
|
|
|
|
|
why is garbage collection impossible (or as least very hard)?
|
|
|
|
|
char *s = malloc(1024); s -= 10000; // nothing points to the allocated memory // region. Could it be garbage collected? s += 10000; // no, because now something points to it again!
|
|
|
|
|
assigned reading for Monday: homework 4
|
|
|