Dynamic Memory Management Bin Li Assistant Professor Dept. of Electrical, Computer and Biomedical Engineering University of Rhode Island 1
Dynamic Memory Allocation Dynamic memory allocation is used to obtain and release memory during program execution. Up until this point we reserved memory at compile time using declarations. You have to be careful with dynamic memory allocation. It operates at a low-level, you will often find yourself having to do a certain amount of work to manage the memory it gives you. To use the functions discussed here, you must include the stdlib.h header file. Four Dynamic Memory Allocation Functions: Allocate memory - malloc(), calloc(), and realloc() Free memory - free()
malloc() To allocate memory use void *malloc(size_t size); Takes number of bytes to allocate as argument. Use sizeof to determine the size of a type. Returns pointer of type void *. A void pointer may be assigned to any pointer. If no memory available, returns NULL. e.g. char *line; int linelength = 100; line = (char*)malloc(linelength);
Allocating memory for a struct You can also allocate memory for a struct. Example: struct node *newptr; newptr = (struct node *)malloc(sizeof(struct node)); Memory allocated with malloc() lasts as long as you want it to. It does not automatically disappear when a function returns, as automatic-duration variables do, but it does not have to remain for the entire duration of your program, either. There is a mechanism to free allocated memory.
free() To release allocated memory use void free(void *p) Deallocates memory allocated by malloc(). Takes a pointer as an argument. e.g. free(newptr); Freeing unused memory is a good idea, but it's not mandatory. When your program exits, any memory which it has allocated but not freed will be automatically released.
malloc Example #include <stdio.h> #include <stdlib.h> void main () { int i, *p; /* Allocate a block of n ints */ p = (int *) malloc(n * sizeof(int)); if (p == NULL) { perror("malloc"); exit(0); } /* Initialize allocated block */ for (i=0; i<n; i++) p[i] = i; } /* Return allocated block to the heap */ free(p);
malloc Example x: a one-dimensional, 10-element array of integers int *x; //int x[10] or #define SIZE 10 int x[size]; x = (int *) malloc(10 * sizeof(int)); If the declaration is to include the assignment of initial values, however, then x must be defined as an array rather than a pointer variable. int x[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 7
calloc() Similar to malloc(), the main difference is that the values stored in the allocated memory space are zero by default. With malloc(), the allocated memory could have any value. calloc() requires two arguments - the number of variables you'd like to allocate memory for and the size of each variable. void *calloc(size_t nitem, size_t size); Like malloc(), calloc() will return a void pointer if the memory allocation was successful, else it'll return a NULL pointer.
realloc() If you find you did not allocate enough space use realloc(). You give realloc() a pointer (such as you received from an initial call to malloc()) and a new size, and realloc does what it can to give you a block of memory big enough to hold the new size. int *ip; ip = (int*)malloc(100 * sizeof(int));... /* need twice as much space */ ip = (int*)realloc(ip, 200 * sizeof(int));
Geo/Geo/1 Simulations Queue dynamics qq kk + 1 = max{qq kk + aa kk ss kk, 0} typedef structure DNode { double atime; // file arrival time int fsize; // file size } File;
Doubly Linked List A doubly linked list provides a natural implementation of the List ADT Nodes implement Position and store: element link to the previous node link to the next node Special trailer and header nodes prev elem next node header nodes/positions trailer elements 11
Sentinel Nodes To simplify programming, two special nodes have been added at both ends of the doubly-linked list. Header and trailer are dummy nodes, also called sentinels, do not store any data elements. Header: header sentinel has a null-prev reference (link). Trailer: trailer sentinel has a null-next reference (link). 12
What we see from a Douby-linked List? A doubly-linked list object would need to store the following: 1. Reference to sentinel header-node; 2. Reference to sentinel trailer-node; and 3. Size-counter that keeps track of the number of nodes in the list (excluding the two sentinels). 13
Empty Doubly-Linked List: Using sentinels, we have no nulllinks; instead, we have: header.next = tail trailer.prev = header Single Node List: Size = 1 This single node is the first node, and also is the last node: first node is header.next last node is trailer.prev header header first trailer last trailer 14
Examples typedef structure DNode { double atime; // file arrival time int fsize; // file size Dnode* prev; //previous node in list Dnode* next; // next node in list } File; typedef structure { File * header; File * trailer; } Queue; //first node in list // last node in list
Operations of Doubly-Linked List IsEmpty: determine whether or not the list is empty AddFile: insert a new node at a particular position Remove: find a node with a given value
IsEmpty() int IsEmpty() { } return (header->next == trailer);
Queue* AddFile(Queue* myqueue, double time, int size) Queue* AddFile(Queue* myqueue, double time, int size) { File* u = (File*)malloc(sizeof(File)); // create a new node u->atime = time; u->fsize = size; File* Lastfile = (File*)malloc(sizeof(File)); Lastfile = myqueue->trailer; u->next = Lastfile; u->prev = Lastfile->prev; trailer w } Lastfile->prev->next = u; Lastfile->prev = u; return myqueue;
Queue* AddFile(Queue* myqueue, double time, int size) Queue* AddFile(Queue* myqueue, double time, int size) { File* u = (File*)malloc(sizeof(File)); // create a new node u->atime = time; u->fsize = size; File* Lastfile = (File*)malloc(sizeof(File)); Lastfile = myqueue->trailer; u->next = Lastfile; u->prev = Lastfile->prev; trailer w Lastfile->prev->next = u; Lastfile->prev = u; u } return myqueue;
Queue* Remove(Queue* myqueue, File* f) Queue* Remove(Queue* myqueue, File* f) { File* u = (File*)malloc(sizeof(File)); File* v = (File*)malloc(sizeof(File)); u = f->prev; v = f->next; // remove Node f } u->next = f->next; v->prev = f->prev; free(f); return myqueue; v f u
Queue* Remove(Queue* myqueue, File* f) Queue* Remove(Queue* myqueue, File* f) { File* u = (File*)malloc(sizeof(File)); File* v = (File*)malloc(sizeof(File)); u = f->prev; v = f->next; // remove Node f } u->next = f->next; v->prev = f->prev; free(f); return myqueue; v u
Queue* RemoveFront(Queue* myqueue) Queue* RemoveFront(Queue* myqueue) { // remove the firstnode myqueue = Remove(myQueue, myqueue->header->next); return myqueue; } w u header
Queue* RemoveFront(Queue* myqueue) Queue* RemoveFront(Queue* myqueue) { // remove the firstnode myqueue = Remove(myQueue, myqueue->header->next); return myqueue; } w header