|
|
|
Lecture 12 — more memory management, hw4, header files
|
|
|
|
|
reminder: check remaining late days, no credit for late work
|
|
|
|
|
midterm review 2 - 3 p.m. on Saturday, room TBD
|
|
|
|
|
heap allocation review
|
|
|
|
|
picture of memory
|
|
|
|
|
void *malloc(size_t size)
|
|
|
|
|
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
|
|
|
|
|
void free(void *ptr)
|
|
|
|
|
if we have typedef struct { char *str; int len; } String;
|
|
|
|
|
exercise: what is the size of String?
|
|
|
|
|
8 bytes for char* + 4 bytes for int = 12 bytes
|
|
|
|
|
we allocate one like this String *s = malloc(sizeof(*s));
|
|
|
|
|
of an array of them like this String *s = malloc(10 * sizeof(*s)); or this String *s = calloc(10, sizeof(*s));
|
|
|
|
|
be aware: with malloc, you will need to initialize members to null if you want to be able to check if they have been initialized
|
|
|
|
|
in any case, free the memory like this free(s);
|
|
|
|
|
be aware: this does not allocate memory for the characters of str, just memory for the pointer itself
|
|
|
|
|
exercise: where is the memory leak?
|
|
|
|
|
int main (int argc, char **argv) { int **matrix; matrix = malloc (3 * sizeof (*matrix)); for (int i = 0; i < 3; i++) { matrix[i] = malloc(5 * sizeof(*matrix[i])); } free(matrix); }
|
|
|
|
|
free is shallow, so while the memory allocated to matrix is freed, the memory allocated to the elements of matrix is not
|
|
|
|
|
header files
|
|
|
|
|
why would we want the ability to separate code into multiple files
|
|
|
|
|
more readable, maintainable
|
|
|
|
|
abstraction
|
|
|
|
|
compilation
|
|
|
|
|
header files (.h files) are how you share code between .c files
|
|
|
|
|
struct definitions, function prototypes (declarations), #defines, and #includes
|
|
|
|
|
no function definitions (leave that to the appropriate .c file)
|
|
|
|
|
putting the #include target in " " searches the current directory (< > searches the standard library)
|
|
|
|
|
can think of .h vs .c as public vs private
|
|
|
|
|
.h in some ways provide an interface
|
|
|
|
|
to avoid problems with double inclusion or mutually recursive inclusion, use #ifndef
|
|
|
|
|
Any header file, such as some_header.h, should begin with #ifndef SOME_HEADER_H #define SOME_HEADER_H // actual header code #endif
|
|
|
|
|
#ifdef and #ifndef are an example of conditional compilation
|
|
|
|
|
the preprocessor uses or discards the enclosed code accordingly
|
|
|
|
|
tests whether something has been #define-ed (or not)
|
|
|
|
|
exercise: write a function debug_printf(char *format_str) that uses the preprocessor define DEBUG to determine whether it prints anything
|
|
|
|
|
void debug_printf(char *output) { #ifdef DEBUG printf(output); #endif return; }
|
|
|
|
|
you can even set something to be defined as part of the gcc command with -D
|
|
|
|
|
gcc -D Debug …
|
|
|
|
|
homework 4
|
|
|
|
|
Implement the T9 (text on 9 keys) system, without the predictive part
|
|
|
|
|
so just the ability to encode words as a series of digits 2-9
|
|
|
|
|
interactive command-line program
|
|
|
|
|
729 -> ‘paw’
|
|
|
|
|
729# -> ‘pax’
|
|
|
|
|
729## -> ‘pay’
|
|
|
|
|
core idea: represent this dictionary using a tree-based data structure called a trie
|
|
|
|
|
the position of a node in the tree defines the key at that node
|
|
|
|
|
organization
|
|
|
|
|
trie data structure
|
|
|
|
|
struct representing a node (recursive data structure)
|
|
|
|
|
functions:
|
|
|
|
|
create/init
|
|
|
|
|
insert
|
|
|
|
|
lookup
|
|
|
|
|
destroy
|
|
|
|
|
trie.h — declarations
|
|
|
|
|
trie.c — implementation
|
|
|
|
|
main
|
|
|
|
|
#include “trie.h”
|
|
|
|
|
probably shouldn’t define any structs, additional functions, etc.
|
|
|