Week 05
Week 05 | 1/48 |
Nerds You Should Know #4 | 2/48 |
... Nerds You Should Know #4 | 3/48 |
Michael Hart
|
|
Dynamic Memory Allocation | 4/48 |
Statically allocated objects ...
... Dynamic Memory Allocation | 5/48 |
Example: write a function lowerCase()
char *old = "This is MY string."; char *new; new = lowerCase(old); print("%s\n%s\n", old, new);// Output: // This is MY string. // this is my string.
Notes:
old
new
tolower(ch)
ctype.h
... Dynamic Memory Allocation | 6/48 |
Attempt #1: use a local string buffer
char *lowerCase(char *str) { char *cp;// input string cursor char *op;// output string cursor char out[BUFSIZ];// output string buffer op = out; for (cp = str; *cp != '\0'; cp++) { *op = tolower(*cp); op++; } *op = '\0'; return out;// what is the precise effect? }
BUG: the out
lowerCase()
... Dynamic Memory Allocation | 7/48 |
Attempt #2: user-supplied string buffer (different interface)
char *old = "This is MY string."; char new[BUFSIZ]; ... lowerCase(old, new); ... void lowerCase(char *in, char *out) { char *cp, *op = out; for (cp = in; *cp != '\0'; cp++) { *op = tolower(*cp); op++; } *op = '\0'; }
More common way of writing loop body: *op++ = tolower(*cp);
... Dynamic Memory Allocation | 8/48 |
Attempt #3: dynamically allocated buffer
char *lowerCase(char *str) { char *cp;// input string cursor char *op;// output string cursor char *out;// output string buffer out = (char *)malloc(strlen(str)+1); assert(out != NULL); op = out; for (cp = str; *cp != '\0'; cp++) { *op = tolower(*cp); op++; } *op = '\0'; return out;// what is the precise effect? }
Memory Management | 9/48 |
void free(void *ptr)
malloc()
*ptr
*ptr
malloc()
free()
... Memory Management | 10/48 |
Warning!
Careless use of malloc()
free()
malloc()
free()
Be very careful with your use of malloc()
free()
... Memory Management | 11/48 |
Given a pointer variable:
NULL
... Memory Management | 12/48 |
Typical usage pattern for dynamically allocated objects:
// single dynamic object e.g. struct size_t size = sizeof(Type); Type *ptr = (Type *)malloc(size); assert(ptr != NULL);... use object referenced by ptr e.g. ptr->name ... free(ptr);// dynamic array with "nelems" elements int nelems = NumberOfElements; size_t eSize = sizeof(ElemType); ElemType *arr = (Type *)malloc(nelems*eSize); assert(arr != NULL);... use array referenced by arr e.g. arr[4] ... free(arr);
Exercise: Flatten a 2d Array | 13/48 |
Implement a function
int *flattenArray(Matrix matrix, int m, int n)
which
Memory Leaks | 14/48 |
Well-behaved programs do the following:
malloc()
free()
free()
Such programs may eventually exhaust available heapspace.
... Memory Leaks | 15/48 |
Example function with memory leak:
int median(int v[], int n) { int i, j, min, tmp, *sorted; sorted = (int *)malloc(n*sizeof(int)); assert(sorted != NULL); for (i = 0; i < n; i++) { sorted[i] = v[i]; } for (i = 0; i < n; i++) {// a simple sorting algorithm min = i; for (j = i+1; j < n; j++) { if (sorted[j] < sorted[min]) { min = j; } } tmp = sorted[i]; sorted[i] = sorted[min]; sorted[min] = tmp; } return sorted[n/2]; }
The array referenced by sorted
... Memory Leaks | 16/48 |
Example function without memory leak:
int median(int v[], int n) { int i, j, min, tmp, med, *sorted; sorted = (int *)malloc(n*sizeof(int)); assert(sorted != NULL); for (i = 0; i < n; i++) { sorted[i] = v[i]; } for (i = 0; i < n; i++) {// a simple sorting algorithm min = i; for (j = i+1; j < n; j++) { if (sorted[j] < sorted[min]) { min = j; } } tmp = sorted[i]; sorted[i] = sorted[min]; sorted[min] = tmp; } med = sorted[n/2]; free(sorted); return med;// would return sorted[n/2]; work? }
The array referenced by sorted
Summary: Memory Management Functions | 17/48 |
void *malloc(size_t nbytes)
nbytes
NULL
... Summary: Memory Management Functions | 18/48 |
void free(void *ptr)
malloc()
*ptr
*ptr
malloc()
free()
... Summary: Memory Management Functions | 19/48 |
void *calloc(size_t nelems, size_t nbytes)
nelems
nbytes
nelems*nbytes
NULL
... Summary: Memory Management Functions | 20/48 |
void *realloc(void *ptr, size_t nbytes)
nbytes
*ptr
free(ptr)
nbytes
*ptr
NULL
free
Exercise: Generic Matrix Library | 21/48 |
Use dynamically allocated memory to implement the following library of Matrix
typedef struct { int nrows, ncols; float **data; } Matrix; int readMatrix(Matrix *); void printMatrix(Matrix); void copyMatrix(Matrix, Matrix); void transMatrix(Matrix, Matrix); void addMatrix(Matrix, Matrix, Matrix); void mulMatrix(Matrix, Matrix, Matrix);
Notes:
readMatrix
nrows
ncols
Dynamic Structures |
Static/Dynamic Sequences | 23/48 |
We have studied arrays extensively
realloc()
... Static/Dynamic Sequences | 24/48 |
Inserting a value into a sorted array (insert(a,&n,4)
... Static/Dynamic Sequences | 25/48 |
Deleting a value from a sorted array (delete(a,&n,3)
Exercise: Insert/Delete in Sorted Array | 26/48 |
Implement the above insert and delete operations:
// insert value v into array a of length n void insert(int *a, int *n, int v);// delete value v from array a of length n void delete(int *a, int *n, int v);
What special cases do we need to consider?
Dynamic Sequences | 27/48 |
The problems with using arrays can be solved by
Benefits:
Self-referential Structures | 28/48 |
To realise a "chain of elements", need a node containing
struct node { int data; struct node *next; };
... Self-referential Structures | 29/48 |
When definining self-referential types with typedef
typedef struct node { int data; struct node *next; } NodeT;
or
typedef struct node NodeT; struct node { int data; NodeT *next; };
... Self-referential Structures | 30/48 |
Note that the following definition does not work:
typedef struct { int data; NodeT *next; } NodeT;
Because NodeT
next
The following is also illegal in C:
struct node { int data; struct node recursive; };
Because the size of the structure would have to satisfy
sizeof(struct node) = sizeof(int) + sizeof(struct node) = ∞
Linked Lists | 31/48 |
To represent a chained (linked) list of nodes:
next
NULL
... Linked Lists | 32/48 |
Linked lists are more flexible than arrays:
next
Memory Storage for Linked Lists | 33/48 |
Linked list nodes are typically located in the heap
... Memory Storage for Linked Lists | 34/48 |
Iteration over Linked Lists | 35/48 |
When manipulating list elements
p
NodeT *p
p->data
p->next
p
p
p
p
NULL
... Iteration over Linked Lists | 36/48 |
Standard method for scanning all elements in a linked list:
NodeT *list;// pointer to first Node in list NodeT *p;// pointer to "current" Node in list p = list; while (p != NULL) {... do something with p->data... p = p->next; }// which is frequently written as for (p = list; p != NULL; p = p->next) {... do something with p->data... }
... Iteration over Linked Lists | 37/48 |
... Iteration over Linked Lists | 38/48 |
Exercise: Print a List | 39/48 |
Write a function that will
'\n'
void printList(NodeT *list) { ... }
Exercise: Length of List | 40/48 |
Write a function that will
int length(NodeT *list) { ... }
Recall: To iterate over a linked list,
p
p
p
p
NULL
List Type | 41/48 |
In the previous examples, we define a list
typedef
typedef struct node { int data; struct node *next; } NodeT; typedef NodeT *List;
The previous functions could then be defined as:
void printList(List list) { ... } int length(List list) { ... }
... List Type | 42/48 |
Common variations on basic List
Store pointers to both first (head) and last (tail) nodes:
typedef struct { NodeT *head; NodeT *tail; } List;
Include a length counter:
typedef struct { NodeT *head; int length; } List;
List Operations | 43/48 |
A typical list datatype would involve operations:
... List Operations | 44/48 |
An important operation used by list operations:
NodeT *makeNode(int v) { NodeT *new; new = (NodeT *)malloc(sizeof(NodeT)); assert(new != NULL); new->data = v; new->next = NULL; return new; }
... List Operations | 45/48 |
NodeT *insertTail(NodeT *head, int d) { // create new node with data NodeT *new = makeNode(d); if (head != NULL) {// check if at least 1 node NodeT *cur; cur = head;// start at the head while (cur->next != NULL) {// this must be defined cur = cur->next; } cur->next = new;// cur->next was NULL } else { head = new;// if no list, list = new } return head; }
... List Operations | 46/48 |
Another important list operation:
void freeList(NodeT *list) { NodeT *cur; cur = list; while (cur != NULL) { NodeT *tmp = cur->next; free(cur); cur = tmp; } }
Exercise: Sorted List Type | 47/48 |
Implement a new SortedIntList
typedef ... SortedIntList; SortedIntList mkEmpty(); void printList(SortedIntList); SortedIntList insert(SortedIntList, int); SortedIntList delete(SortedIntList, int);
Tips for Next Week's Lab | 48/48 |
Memory management, Linked lists
malloc()
malloc()
char *heap = (char *)malloc( ... )
free(heap);
heapsum.c
NodeT *makeNode(int value); freeList(NodeT *head); NodeT *insertTail(NodeT *head, int value);
void printList(NodeT *head);
sample output: 10->20->30->40
Produced: 19 Aug 2016