V Lecture 11 — memory and the heap
V why dynamic allocation?
V can you define a struct for a linked list of ints?
V struct node {
int data;
struct node next;
}
* generates compiler error
V struct node {
int data;
struct node *next;
}
* will compile, but how to we create the node next points to?
V picture of memory
V stack allocation
* stores local variables
* automatically allocated when a function is called
V 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
V heap allocation
* manually allocated
* arbitrary size
* manually deallocated
V 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)
V void* gets automatically promoted to the type of the left-hand side
* char *s = malloc(10); // no need for a cast
V but, not uncommon to include cast, especially since C++ requires it
* char *s = (char*)malloc(10);
V 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
V 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));
V sizeof is its own special thing
* can be applied to types or values
* ( ) optional, but useful for clarity
V void free(void *ptr)
* deallocate memory pointed to by ptr
V 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
V 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);
}
V 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;
}
V exercise: where is the memory leak?
V 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
V void f() {
int *nums = malloc(10 * sizeof(*nums));
// do stuff with nums
return;
}
* once f returns, nothing points to the memory allocated to nums
V 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