1 / 97

CSC 211 Data Structures Lecture 6

CSC 211 Data Structures Lecture 6. Dr. Iftikhar Azim Niaz ianiaz@comsats.edu.pk. 1. Last Lecture Summary I. Concept of Pointer Pointer operators Address and Indirection Pointer Arithmetic Pointer and functions Pass by Value Pass by Reference Pointer and Arrays. 2. Objectives Overview.

linus
Download Presentation

CSC 211 Data Structures Lecture 6

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. CSC 211Data StructuresLecture 6 Dr. Iftikhar Azim Niaz ianiaz@comsats.edu.pk 1

  2. Last Lecture Summary I • Concept of Pointer • Pointer operators • Address and Indirection • Pointer Arithmetic • Pointer and functions • Pass by Value • Pass by Reference • Pointer and Arrays 2

  3. Objectives Overview • Dynamic Memory Management with Pointers • Structures • Unions • Strings • Multidimensional Arrays

  4. Dynamic Memory Allocation • Static memory - where global and static variables live • Heap memory - dynamically allocated at execution time - "managed" memory accessed using pointers • Stack memory - used by automatic variables In C and C++, three types of memory are used by programs:

  5. 3 Kinds of Program Data • STATIC DATA: Allocated at compiler time • DYNAMIC DATA: explicitly allocated and deallocated during program execution by C++ instructions written by programmer using operators new and delete • AUTOMATIC DATA: automatically created at function entry, resides in activation frame of the function, and is destroyed when returning from function

  6. Dynamic Memory Allocation Diagram

  7. Allocation of Memory • Static Allocation: Allocation of memory space at compile time. • Dynamic Allocation: Allocation of memory space at run time. • Dynamic allocation is useful when • arrays need to be created whose extent is not known until run time • complex structures of unknown size and/or shape need to be constructed as the program runs • objects need to be created and the constructor arguments are not known until run time

  8. Stack-allocated memory When a function is called, memory is allocated for all of its parameters and local variables. Each active function call has memory on the stack (with the current function call on top) When a function call terminates, the memory is deallocated (“freed up”) Ex: main() calls f(), f() calls g() g() recursively calls g() Overview of memory management g() g() f() main()

  9. Heap-allocated memory This is used for persistent data, that must survive beyond the lifetime of a function call global variables dynamically allocated memory – C statements can create new heap data (similar to new in Java/C++) Heap memory is allocated in a more complex way than stack memory Like stack-allocated memory, the underlying system determines where to get more memory – the programmer doesn’t have to search for free memory space! Overview of memory management

  10. void *malloc(size_t size); Allocate a block of size bytes, return a pointer to the block (NULL if unable to allocate block) void *calloc(size_tnum_elements, size_telement_size); Allocate a block of num_elements * element_size bytes, initialize every byte to zero, return pointer to the block (NULL if unable to allocate block) Note: void * denotes a generic pointer type Allocating new heap memory

  11. void *realloc(void *ptr, size_tnew_size); Given a previously allocated block starting at ptr, change the block size to new_size, return pointer to resized block If block size is increased, contents of old block may be copied to a completely different region In this case, the pointer returned will be different from the ptr argument, and ptr will no longer point to a valid memory region If ptr is NULL, realloc is identical to malloc Note: may need to cast return value of malloc/calloc/realloc: char *p = (char *) malloc(BUFFER_SIZE); Allocating new heap memory

  12. void free(void *pointer); Given a pointer to previously allocated memory, put the region back in the heap of unallocated memory Note: easy to forget to free memory when no longer needed... especially if you’re used to a language with “garbage collection” like Java This is the source of the notorious “memory leak” problem Difficult to trace – the program will run fine for some time, until suddenly there is no more memory! Deallocating heap memory

  13. Call to malloc might fail to allocate memory, if there’s not enough available Easy to forget this check, annoying to have to do it every time malloc is called... solution: #define malloc DON’T CALL malloc DIRECTLY! #define MALLOC(num,type) (type *)alloc((num)*sizeof(type)) extern void *alloc(size_t size); Checking for successful allocation Garbage inserted into source code if programmer uses malloc Use MALLOC instead... Scales memory region appropriately (Note use of parameters in #define) Also, calls “safe” alloc function

  14. implementation of alloc: #undefmalloc void *alloc(size_t size) { void *new_mem; new_mem = malloc(size); if (new_mem == NULL) exit(1); return new_mem; } Nice solution – as long as “terminate the program” is always the right response Checking for successful allocation

  15. Using memory that you have not initialized Using memory that you do not own Using more memory than you have allocated Using faulty heap memory management Memory errors

  16. Uninitialized memory read Uninitialized memory copy not necessarily critical – unless a memory read follows void foo(int *pi) { int j; *pi = j; /* UMC: j is uninitialized, copied into *pi */ } void bar() { inti=10; foo(&i); printf("i = %d\n", i); /* UMR: Using i, which is now junk value */ } Using memory that you have not initialized

  17. Null pointer read/write Zero page read/write typedefstruct node { struct node* next; intval; } Node; intfindLastNodeValue(Node* head) { while (head->next != NULL) { /* Expect NPR */ head = head->next; } return head->val; /* Expect ZPR */ } Using memory that you don’t own What if head is NULL?

  18. Invalid pointer read/write Pointer to memory that hasn’t been allocated to program void genIPR() { int *ipr = (int *) malloc(4 * sizeof(int)); inti, j; i = *(ipr - 1000); j = *(ipr + 1000); /* Expect IPR */ free(ipr); } void genIPW() { int *ipw = (int *) malloc(5 * sizeof(int)); *(ipw - 1000) = 0; *(ipw + 1000) = 0; /* Expect IPW */ free(ipw); } Using memory that you don’t own

  19. Common error in 64-bit applications: ints are 4 bytes but pointers are 8 bytes If prototype of malloc() not provided, return value will be cast to a 4-byte int /*Forgot to #include <malloc.h>, <stdlib.h> in a 64-bit application*/ void illegalPointer() { int *pi = (int*) malloc(4 * sizeof(int)); pi[0] = 10; /* Expect IPW */ printf("Array value = %d\n", pi[0]); /* Expect IPR */ } Using memory that you don’t own Four bytes will be lopped off this value – resulting in an invalid pointer value

  20. Free memory read/write Access of memory that has been freed earlier int* init_array(int *ptr, intnew_size) { ptr = (int*) realloc(ptr, new_size*sizeof(int)); memset(ptr, 0, new_size*sizeof(int)); return ptr; } int* fill_fibonacci(int *fib, int size) { inti; /* oops, forgot: fib = */ init_array(fib, size); /* fib[0] = 0; */ fib[1] = 1; for (i=2; i<size; i++) fib[i] = fib[i-1] + fib[i-2]; return fib; } Using memory that you don’t own Remember: realloc may move entire block What if array is moved to new location?

  21. Beyond stack read/write char *append(const char* s1, const char *s2) { const int MAXSIZE = 128; char result[128]; inti=0, j=0; for (j=0; i<MAXSIZE-1 && j<strlen(s1); i++,j++) { result[i] = s1[j]; } for (j=0; i<MAXSIZE-1 && j<strlen(s2); i++,j++) { result[i] = s2[j]; } result[++i] = '\0'; return result; } Using memory that you don’t own result is a local array name – stack memory allocated Function returns pointer to stack memory – won’t be valid after function returns

  22. Array bound read/write void genABRandABW() { const char *name = “Safety Critical"; char *str = (char*) malloc(10); strncpy(str, name, 10); str[11] = '\0'; /* Expect ABW */ printf("%s\n", str); /* Expect ABR */ } Using memory that you haven’t allocated

  23. Memory leak int *pi; void foo() { pi = (int*) malloc(8*sizeof(int)); /* Allocate memory for pi */ /* Oops, leaked the old memory pointed to by pi */ … free(pi); /* foo() is done with pi, so free it */ } void main() { pi = (int*) malloc(4*sizeof(int)); /* Expect MLK: foo leaks it */ foo(); } Faulty heap management

  24. Potential memory leak no pointer to the beginning of a block not necessarily critical – block beginning may still be reachable via pointer arithmetic int *plk = NULL; void genPLK() { plk = (int *) malloc(2 * sizeof(int)); /* Expect PLK as pointer variable is incremented past beginning of block */ plk++; } Faulty heap management

  25. Freeing non-heap memory Freeing unallocated memory void genFNH() { intfnh = 0; free(&fnh); /* Expect FNH: freeing stack memory */ } void genFUM() { int *fum = (int *) malloc(4 * sizeof(int)); free(fum+1); /* Expect FUM: fum+1 points to middle of a block */ free(fum); free(fum); /* Expect FUM: freeing already freed memory */ } Faulty heap management

  26. Definition — The Heap • A region of memory provided by most operating systems for allocating storage not in Last in, First out discipline • I.e., not a stack • Must be explicitly allocated and released • May be accessed only with pointers • Remember, an array is equivalent to a pointer • Many hazards to the C programmer

  27. 0xFFFFFFFF stack (dynamically allocated) SP heap (dynamically allocated) address space static data program code (text) PC 0x00000000 This is The Heap. Static Data Allocation

  28. Allocating Memory in The Heap • See <stdlib.h> void *malloc(size_t size); void free(void *ptr); void *calloc(size_tnmemb, size_t size); void *realloc(void *ptr, size_t size); • malloc() — allocates size bytes of memory from the heap and returns a pointer to it. • NULL pointer if allocation fails for any reason • free() — returns the chunk of memory pointed to by ptr • Must have been allocated by malloc or calloc

  29. Segmentation fault and/or big-time error if bad pointer Allocating Memory in The Heap • See <stdlib.h> void *malloc(size_t size); void free(void *ptr); void *calloc(size_tnmemb, size_t size); void *realloc(void *ptr, size_t size); • malloc() — allocates size bytes of memory from the heap and returns a pointer to it. • NULL pointer if allocation fails for any reason • free() — returns the chunk of memory pointed to by ptr • Must have been allocated by malloc or calloc

  30. free() knows size of chunk allocated by malloc() or calloc() Allocating Memory in The Heap • See <stdlib.h> void *malloc(size_t size); void free(void *ptr); void *calloc(size_tnmemb, size_t size); void *realloc(void *ptr, size_t size); • malloc() — allocates size bytes of memory from the heap and returns a pointer to it. • NULL pointer if allocation fails for any reason • free() — returns the chunk of memory pointed to by ptr • Must have been allocated by malloc or calloc

  31. Notes • calloc() is just a variant of malloc() • malloc() is analogous to new in C++ and Java • new in C++ actually calls malloc() • free() is analogous to delete in C++ • delete in C++ actually calls free() • Java does not have delete — uses garbage collection to recover memory no longer in use

  32. Typical usage of malloc() and free() char *getTextFromSomewhere(…); int main(){ char * txt; …; txt = getTextFromSomewhere(…); …; printf("The text returned is %s.", txt); free(txt); }

  33. getTextFromSomewhere() creates a new string using malloc() Typical usage of malloc() and free() char * getTextFromSomewhere(…){char *t;...t = malloc(stringLength);...return t; } int main(){ char * txt; …; txt = getTextFromSomewhere(…); …; printf("The text returned is %s.", txt); free(txt); }

  34. Pointer to text is assigned to txt in calling function Typical usage of malloc() and free() char * getTextFromSomewhere(…){char *t;...t = malloc(stringLength);...return t; } int main(){ char * txt; …; txt = getTextFromSomewhere(…); …; printf("The text returned is %s.", txt); free(txt); }

  35. main() must remember to free the storage pointed to by txt Usage of malloc() and free() char *getText(…){char *t;...t = malloc(stringLength);...return t; } int main(){ char * txt; …; txt = getText(…); …; printf("The text returned is %s.", txt); free(txt); }

  36. Definition – Memory Leak • The steady loss of available memory due to forgetting to free() everything that was malloc’ed. • Bug-a-boo of most large C and C++ programs • If you “forget” the value of a pointer to a piece of malloc’ed memory, there is no way to find it again! • Killing the program frees all memory!

  37. Dynamic Memory Allocation in C++ • In C, functions such as malloc() are used to dynamically allocate memory from the Heap. • In C++, this is accomplished using the new and delete operators • new is used to allocate memory during execution time • returns a pointer to the address where the object is to be stored • always returns a pointer to the type that follows thenew

  38. Operator new Syntax new DataType new DataType [IntExpression] • If memory is available, in an area called the heap (or free store) new allocates the requested object or array, and returns a pointerto (address of ) the memory allocated. • Otherwise, program terminates with error message. • The dynamically allocated object exists until the delete operator destroys it.

  39. Operator new char* ptr; ptr = new char; *ptr = ‘B’; cout << *ptr; NOTE:Dynamic data has no variable name 2000 ??? ptr 5000 5000 ‘B’

  40. The NULL Pointer • There is a pointer constant called the “null pointer” denoted by NULL • But NULL is not memory address 0. • NOTE: It is an error to dereference a pointer whose value is NULL. Such an error may cause your program to crash, or behave erratically. It is the programmer’s job to check for this. while (ptr != NULL) { . . . // ok to use *ptr here }

  41. Operator delete Syntax delete Pointer delete [ ] Pointer • The object or array currently pointed to by Pointer is deallocated, and the value of Pointer is undefined. The memory is returned to the free store. • Good idea to set the pointer to the released memory to NULL • Square brackets are used with delete to deallocate a dynamically allocated array.

  42. Operator delete char* ptr; ptr = new char; *ptr = ‘B’; cout << *ptr; delete ptr; 2000 ptr 5000 ??? 5000 ‘B’ NOTE: delete deallocates the memory pointed to by ptr

  43. 3000 ptr ??? ‘u’ Example char *ptr ; ptr = new char[ 5 ]; strcpy( ptr, “Bye” ); ptr[ 0 ] = ‘u’; delete [] ptr; ptr = NULL; 6000 NULL ??? 6000 ‘B’ ‘y’ ‘e’ ‘\0’ // deallocates the array pointed to by ptr // ptr itself is not deallocated // the value of ptr becomes undefined

  44. Memory leaks • When you dynamically create objects, you can access them through the pointer which is assigned by the new operator • Reassigning a pointer without deleting the memory it pointed to previously is called a memory leak • It results in loss of available memory space

  45. ptr1 8 ptr2 5 ptr1 8 ptr2 5 Memory leak example int *ptr1 = new int; int *ptr2 = new int; *ptr1 = 8; *ptr2 = 5; ptr2 = ptr1; How to avoid?

  46. Inaccessible object • An inaccessible object is an unnamed object that was created by operator new and which a programmer has left without a pointer to it. • It is a logical error and causes memory leaks.

  47. Dangling Pointer • It is a pointer that points to dynamic memory that has been deallocated. • The result of dereferencing a dangling pointer is unpredictable.

  48. ptr1 8 ptr2 ptr1 ptr2 Dangling Pointer example int *ptr1 = new int; int *ptr2; *ptr1 = 8; ptr2 = ptr1; delete ptr1; How to avoid?

  49. Dynamic Arrays • You would like to use an array data structure but you do not know the size of the array at compile time. • You find out when the program executes that you need an integer array of size n=20. • Allocate an array using the new operator:int* y = new int[20]; // or int* y = new int[n]y[0] = 10;y[1] = 15; // use is the same

  50. Dynamic Arrays • ‘y’ is a lvalue; it is a pointer that holds the address of 20 consecutive cells in memory. • It can be assigned a value. The new operator returns as address that is stored in y. • We can write: y = &x[0]; y = x; // x can appear on the right // y gets the address of the // first cell of the x array

More Related