monday week 05
play

Monday Week 05 *op = '\0'; return out; // what is the precise - PowerPoint PPT Presentation

} Monday Week 05 *op = '\0'; return out; // what is the precise effect? } 1/36 Dynamic Memory Allocation BUG: the out variable is removed when lowerCase() returns. Statically allocated objects ... ... Dynamic Memory Allocation 4/36 are


  1. } Monday Week 05 *op = '\0'; return out; // what is the precise effect? } 1/36 Dynamic Memory Allocation BUG: the out variable is removed when lowerCase() returns. Statically allocated objects ... ... Dynamic Memory Allocation 4/36 are allocated by the compiler (to global/stack areas) have a fixed size which is known at compile time Attempt #2: user-supplied string buffer (different interface) have a lifetime determined by location (global/stack) char *old = "This is MY string."; Dynamically allocated objects ... char new[BUFSIZ]; ... are allocated by the executing program (in heap) lowerCase(old, new); have a size which is known at allocation time ... exist until explicitly removed by program void lowerCase(char *in, char *out) { char *cp, *op = out; for (cp = in; *cp != '\0'; cp++) { ... Dynamic Memory Allocation 2/36 *op = tolower(*cp); op++; Example: function to return a lower-cased version of a string } *op = '\0'; char *old = "This is MY string."; } char *new; More common way of writing loop body: *op++ = tolower(*cp); new = lowerCase(old); print("%s\n%s\n", old, new); ... Dynamic Memory Allocation 5/36 // Output: // This is MY string. Attempt #3: dynamically allocated buffer // this is my string. char *lowerCase(char *str) { Notes: char *cp; // input string cursor the old string is unchanged, so the function is making a new copy char *op; // output string cursor old is a pointer to a string in the global data area char *out; // output string buffer new has no string buffer unless it's made to point at one tolower(ch) function in ctype.h is useful here op = out = (char *)malloc(strlen(str)+1); assert(out != NULL); for (cp = str; *cp != '\0'; cp++) { 3/36 ... Dynamic Memory Allocation *op = tolower(*cp); op++; Attempt #1: use a local string buffer } *op = '\0'; char *lowerCase(char *str) { return out; // what is the precise effect? char *cp; // input string cursor } char *op; // output string cursor char out[BUFSIZ]; // output string buffer 6/36 Memory Management op = out; for (cp = str; *cp != '\0'; cp++) { *op = tolower(*cp); void free(void *ptr) op++;

  2. releases a block of memory allocated by malloc() 10/36 Exercise: Making Sentences *ptr is a dynamically allocated object if *ptr was not malloc() 'd, chaos will follow Implement a function Things to note: char *makeSentence(char *strings[]) the contents of the memory block are not changed which all pointers to the block still exist, but are not valid the memory may be re-used as soon as it is free() 'd takes an array of strings (e.g. argv[] ) returns a new string made by concatenating strings with original strings separated by a space in new string 7/36 ... Memory Management assume that strings[] is terminated by a NULL element Warning! Warning! Warning! Warning! 11/36 Memory Leaks Careless use of malloc() / free() / pointers Well-behaved programs do the following: can mess up the data in the heap so that later malloc() or free() cause run-time errors allocate a new object via malloc() possibly well after the original error occurred use the object for as long as needed free() the object when no longer needed Such errors are very difficult to track down and debug. A program which does not free() each object before the last reference to it is lost contains a memory Be very careful with your use of malloc() / free() / pointers. leak . Such programs may eventually exhaust available heapspace. ... Memory Management 8/36 Given a pointer variable: 12/36 ... Memory Leaks you can check whether its value is NULL Example function with memory leak: you can (maybe) check that it is an address you cannot check whether it is a valid address int median(int v[], int n) { int i, j, min, tmp, *sorted; ... Memory Management 9/36 sorted = (int *)malloc(n*sizeof(int)); assert(sorted != NULL); Typical usage pattern for dynamically allocated objects: for (i = 0; i < n; i++) { sorted[i] = v[i]; } // single dynamic object e.g. struct size_t size = sizeof( Type ); for (i = 0; i < n; i++) { Type *ptr = ( Type *)malloc(size); min = i; for (j = i+1; j < n; j++) { assert(ptr != NULL); if (sorted[j] < sorted[min]) ... use object referenced by ptr e.g. ptr->name ... min = j; free(ptr); } tmp = sorted[i]; // dynamic array with "nelems" elements sorted[i] = sorted[min]; sorted[min] = tmp; int nelems = NumberOfElements ; } size_t eSize = sizeof( ElemType ); return sorted[n/2]; ElemType *arr = ( Type *)malloc(nelems*eSize); } assert(arr != NULL); ... use array referenced by arr e.g. arr[4] ... The array referenced by sorted exists after function returns. free(arr);

  3. 13/36 the memory may be re-used as soon as it is free() 'd ... Memory Leaks Example function without memory leak: 16/36 ... Memory Management Functions int median(int v[], int n) { void *realloc(void *ptr, size_t nbytes) int i, j, min, tmp, med, *sorted; aim: increase the size of an array sorted = (int *)malloc(n*sizeof(int)); allocates a memory block of size nb bytes assert(sorted != NULL); if successful, copies all data from *ptr object into it for (i = 0; i < n; i++) { sorted[i] = v[i]; } after copying, performs free(ptr) assumes that nb is larger than size of *ptr object for (i = 0; i < n; i++) { if insufficient memory, returns NULL and does not free min = i; for (j = i+1; j < n; j++) { if (sorted[j] < sorted[min]) min = j; 17/36 ... Memory Management Functions } tmp = sorted[i]; void *calloc(size_t nelems, size_t nbytes) sorted[i] = sorted[min]; sorted[min] = tmp; } aim: create a new array with memory zero'd med = sorted[n/2]; nelems is the number of elements free(sorted); nbytes is the size of each element return med; // would return sorted[n/2]; work? allocates a memory block of size nelems*nbytes bytes } if successful, all bytes in memory block are set to zero The array referenced by sorted is cleaned up before function returns. if insufficient memory, returns NULL 14/36 18/36 Memory Management Functions Exercise: Generic Matrix Library void *malloc(size_t nbytes) Use dynamically allocated memory to implement the following library of Matrix operations: aim: allocate some memory for a data object typedef struct { int nrows, ncols; float **data; } Matrix; attempt to allocate a block of memory of size nbytes in the heap int readMatrix(Matrix *); if successful, returns a pointer to the start of the block void printMatrix(Matrix); if insufficient space in heap, returns NULL void copyMatrix(Matrix, Matrix); void transMatrix(Matrix, Matrix); Things to note: void addMatrix(Matrix, Matrix, Matrix); void mulMatrix(Matrix, Matrix, Matrix); the initial contents of the memory block are random returned address should be cast to appropriate pointer type Notes: readMatrix reads nrows , ncols , then the data 15/36 ... Memory Management Functions can only add matrices with equal rows and columns can only multiply an n × m matrix with an m × p matrix void free(void *ptr) releases a block of memory allocated by malloc() Dynamic Structures *ptr is a dynamically allocated object if *ptr was not malloc() 'd, chaos will follow 20/36 Static/Dynamic Sequences Things to note: the contents of the memory block are not changed We have studied arrays extensively all pointers to the block still exist, but are not valid

  4. fixed size collection of heterogeneous elements What special cases do we need to consider? can be accessed via index or via "moving" pointer The "fixed size" aspect is a potential problem: 24/36 Dynamic Sequences how big to make the array? (big ... just in case) The problems with using arrays can be solved by what to do if it fills up? ( realloc() may help) allocating elements individually The rigid sequence is another problems: linking them together as a "chain" inserting/deleting an item in middle of array 21/36 ... Static/Dynamic Sequences Benefits: Inserting a value into a sorted array ( insert(a,&n,4) ): insertion/deletion have minimal effect on list overall only use as much space as needed for values 25/36 Self-referential Structures To realise a "chain of elements", need a node containing a value a link to the next node In C, we can define such nodes as: ... Static/Dynamic Sequences 22/36 struct node { int data; struct node *next; Deleting a value from a sorted array ( delete(a,&n,3) ): }; 26/36 ... Self-referential Structures When definining self-referential types with typedef typedef struct node { int data; struct node *next; } NodeT; 23/36 Exercise: Insert/Delete in Sorted Array or Implement the above insert and delete operations: typedef struct node NodeT; struct node { // insert value v into array a of length n int data; void insert(int *a, int *n, int v); NodeT *next; }; // delete value v from array a of length n 27/36 void delete(int *a, int *n, int v); ... Self-referential Structures

Recommend


More recommend