C programming Language Chapter 6 Dynamic Memory Allocation

  • Slides: 42
Download presentation
C programming Language Chapter 6: Dynamic Memory Allocation (DMA) ספטמבר 04 Copyright Meir Kalech

C programming Language Chapter 6: Dynamic Memory Allocation (DMA) ספטמבר 04 Copyright Meir Kalech 1

What is Dynamic Memory Allocation? n The problem: Array definition: its size must be

What is Dynamic Memory Allocation? n The problem: Array definition: its size must be known at compilation time. The array, when used, may be either too small – not enough room for all the elements, or too big – so it’s a waste of memory. n The solution: Use Dynamic Memory Allocation (DMA): create the array at run-time, after determining the required number of elements. n Dynamic memory allocation enables the programmer to: n Request exactly the required amount of memory. n Release the allocated memory when it is no longer needed. ספטמבר 04 Copyright Meir Kalech 2

malloc Function n n malloc function enables to allocate memory at run-time. Syntax: malloc(number

malloc Function n n malloc function enables to allocate memory at run-time. Syntax: malloc(number of requested bytes); Example: int size; printf(“how many integers? ”); scanf(“%d”, &size); malloc(size*sizeof(int)); Comment: All the allocation functions use the <alloc. h> library. ספטמבר 04 Copyright Meir Kalech 3

calloc Function n calloc function enables to allocate memory at run time. n n

calloc Function n calloc function enables to allocate memory at run time. n n The allocated memory is initialized (cleared) with zeros. Syntax: calloc(number of elements, size of each element); Example: int size; printf(“how many integers? ”); scanf(“%d”, &size); calloc(size, sizeof(int)); ספטמבר 04 Copyright Meir Kalech FINE! But I can’t access the allocated memory!? 4

Allocation n malloc and calloc return the first address of the allocated memory. Upon

Allocation n malloc and calloc return the first address of the allocated memory. Upon failure, they return NULL (0). We can save the return value in a pointer, and access the memory by using the operator * or operator []. For instance: DON’T int size; WORRY!!! Pointers will int *pointer; help you! printf(“how many integers? ”); scanf(“%d”, &size); pointer = malloc(size*sizeof(int)); if(pointer != NULL) pointer[0] = 54; ספטמבר 04 Copyright Meir Kalech 5

Allocation pointer = malloc(size*sizeof(int)); Problem: What type does malloc return? int *, char *,

Allocation pointer = malloc(size*sizeof(int)); Problem: What type does malloc return? int *, char *, float * ? ? ? Answer: void * !!! void * may be changed to any pointer type by using casting. pointer = (int *) malloc(size*sizeof(int)); ספטמבר 04 Copyright Meir Kalech 6

Heap n n n Where is the memory allocated? Reminder: we studied about the

Heap n n n Where is the memory allocated? Reminder: we studied about the “stack segment” and “data segment”. Stack segment is dedicated to local variables. Allocated memory is not a local variable. Conclusion: dynamic memory is allocated in the data segment (heap). int *p = (int *) malloc(5*sizeof(int)); Stack segment: p: 100 ספטמבר 04 500 Data segment: 500 ? ? ? Copyright Meir Kalech 7

Comment BE CAREFUL: A pointer that points to allocated memory can be mistakenly assigned

Comment BE CAREFUL: A pointer that points to allocated memory can be mistakenly assigned to another memory address. In this case, we might lose our connection to the previously allocated memory. int *p = (int *) malloc(5*sizeof(int)); Stack segment: p: 100 500 ספטמבר 04 Data segment: 500 ? ? ? Copyright Meir Kalech 8

Comment BE CAREFUL: A pointer that points to allocated memory can be mistakenly assigned

Comment BE CAREFUL: A pointer that points to allocated memory can be mistakenly assigned to another memory address. In this case, we might lose our connection to the previously allocated memory. int *p = (int *) malloc(5*sizeof(int)); int arr[3]; p = arr; Stack segment: 500 p: 100 200 arr: 200 ספטמבר 04 Data segment: ? ? ? NOW NOT ACCESSIBLE!! Copyright Meir Kalech 9

Comment To avoid this problem, we can first save the address in another pointer:

Comment To avoid this problem, we can first save the address in another pointer: int *save, *p = (int *) malloc(5*sizeof(int)); int arr[3]; save = p; p = arr; Stack segment: save: 300 p: 100 200 arr: 200 ספטמבר 04 500 ? ? ? Data segment: 500 ? ? ? ACCESSIBLE through save Copyright Meir Kalech 10

free Function n n Since dynamic memory is allocated in the data segment, it

free Function n n Since dynamic memory is allocated in the data segment, it is not deleted when the end of a block is reached, but it’s the programmer responsibility to explicitly delete it. The free function gets the first address of an allocated memory, and frees it: n Syntax: free(first_address); ספטמבר 04 Copyright Meir Kalech 11

free Function int *p 1, *p 2; p 1 = (int *) malloc(5*sizeof(int)); p

free Function int *p 1, *p 2; p 1 = (int *) malloc(5*sizeof(int)); p 2 = (int *) malloc(3*sizeof(int)); free(p 2); free(p 1); Stack segment: p 1: 100 500 p 2: 200 300 ספטמבר 04 Data segment: 500 ? ? ? 300 ? ? ? Copyright Meir Kalech 12

free Function int *p 1, *p 2; p 1 = (int *) malloc(5*sizeof(int)); p

free Function int *p 1, *p 2; p 1 = (int *) malloc(5*sizeof(int)); p 2 = (int *) malloc(3*sizeof(int)); free(p 2); free(p 1); Stack segment: Data segment: p 1: 100 500 p 2: 200 300 ספטמבר 04 Copyright Meir Kalech 13

free Function BE CAREFUL!!! Avoid freeing memory that is already freed (execution error) Stack

free Function BE CAREFUL!!! Avoid freeing memory that is already freed (execution error) Stack segment: int *p 1, *p 2; p 1 = (int *) malloc(5*sizeof(int)); p 2 = (int *) malloc(3*sizeof(int)); free(p 2); free(p 1); Data segment: p 1: 100 500 p 2: 200 300 ספטמבר 04 Copyright Meir Kalech 14

free Function int *p 1, *p 2 Initialize your pointers with NULL! Now, there

free Function int *p 1, *p 2 Initialize your pointers with NULL! Now, there is no BUG. p 1 = (int *) malloc(5*sizeof(int)); p 2 = (int *) malloc(3*sizeof(int)); free(p 2); free(p 1); p 1=NULL; free(p 1); Stack segment: p 1: 100 Data segment: 0 p 2: 200 300 ספטמבר 04 Copyright Meir Kalech 15

String Allocation n For array allocation, the programmer gets the size from the user.

String Allocation n For array allocation, the programmer gets the size from the user. On the other hand, for string allocation, it doesn’t make sense to ask the user for the size, since the meaning of a string size is its number of letters. Therefore, it is common to define a buffer (of length fit for a large string) to store the input string and allocate memory according to the size of the input string. ספטמבר 04 Copyright Meir Kalech 16

String Allocation char *p 1, buffer[30]; printf(“enter string”); scanf(“%s”, buffer); p 1 = (char

String Allocation char *p 1, buffer[30]; printf(“enter string”); scanf(“%s”, buffer); p 1 = (char *) malloc(strlen(buffer)+1); strcpy(p 1, buffer); free(p 1); Stack segment: p 1: 100 Data segment: ? buffer: ? ? ? … ? 200 ספטמבר 04 Copyright Meir Kalech 17

String Allocation char *p 1, buffer[30]; printf(“enter string”); scanf(“%s”, buffer); p 1 = (char

String Allocation char *p 1, buffer[30]; printf(“enter string”); scanf(“%s”, buffer); p 1 = (char *) malloc(strlen(buffer)+1); strcpy(p 1, buffer); free(p 1); Input: “zion” Stack segment: p 1: 100 buffer: z 200 ספטמבר 04 Data segment: ? i o n … ? Copyright Meir Kalech 18

String Allocation char *p 1, buffer[30]; printf(“enter string”); scanf(“%s”, buffer); p 1 = (char

String Allocation char *p 1, buffer[30]; printf(“enter string”); scanf(“%s”, buffer); p 1 = (char *) malloc(strlen(buffer)+1); strcpy(p 1, buffer); free(p 1); Stack segment: p 1: 100 500 buffer: z 200 ספטמבר 04 Data segment: 500 ? ? ? i o n … ? Copyright Meir Kalech 19

String Allocation char *p 1, buffer[30]; printf(“enter string”); scanf(“%s”, buffer); p 1 = (char

String Allocation char *p 1, buffer[30]; printf(“enter string”); scanf(“%s”, buffer); p 1 = (char *) malloc(strlen(buffer)+1); strcpy(p 1, buffer); free(p 1); Stack segment: p 1: 100 500 buffer: z i 200 ספטמבר 04 Data segment: 500 z i o n … ? Copyright Meir Kalech 20

String Allocation char *p 1, buffer[30]; printf(“enter string”); scanf(“%s”, buffer); p 1 = (char

String Allocation char *p 1, buffer[30]; printf(“enter string”); scanf(“%s”, buffer); p 1 = (char *) malloc(strlen(buffer)+1); strcpy(p 1, buffer); free(p 1); Stack segment: Data segment: p 1: 100 500 buffer: z 200 ספטמבר 04 i o n … ? Copyright Meir Kalech 21

realloc Function n One of the goals of dynamic memory allocation is to enable

realloc Function n One of the goals of dynamic memory allocation is to enable reallocation, namely, increase/decrease the old allocation size. There is reallocation function called realloc. n Example: n int size, size 2; int *pointer; printf(“how many integers? ”); scanf(“%d”, &size); pointer = (int *) malloc(size*sizeof(int)); if(pointer == NULL) exit(1); printf(“how many integers more? ”); scanf(“%d”, &size 2); pointer = (int *) realloc(pointer, (size+size 2)*sizeof(int)); if(pointer == NULL) exit(1); ספטמבר 04 Copyright Meir Kalech 22

realloc Function Some Comments: 1. The new size is the old + additional size.

realloc Function Some Comments: 1. The new size is the old + additional size. 2. The process: n If there is enough space • extend the old allocation. n Else • Allocate new size (old + additional). • Copy the old data to the new place. • Free the old allocation (should not be used anymore). Return the first address of the allocation. If the first parameter is NULL, then just malloc. n 3. ספטמבר 04 Copyright Meir Kalech 23

Array of Pointers n n The problem: Assume we want to read a list

Array of Pointers n n The problem: Assume we want to read a list of 3 names. The names differ in length but the maximum name length is 23. First solution: char arr[3][23]; A list of names is an array of strings. Since a string is an array of char, we have a 2 D array of char. Can cause waste of memory!!! 100 S n o w w h i t e r e d r i d i n g 123 L i t t l e h o o d 146 C i n d e r e l l a ספטמבר 04 Copyright Meir Kalech 24

Array of Pointers n Second solution: char *arr[3]; arr is array of 3 elements,

Array of Pointers n Second solution: char *arr[3]; arr is array of 3 elements, where each of them is a pointer to char. Now each element can point to a different char array of a different size. arr: 100 200 340 730 ספטמבר 04 S n L i C o w w h t t l e i n d e i t r e d r e l e r i d i n g l h o o d a Copyright Meir Kalech 25

Pointer to Pointer n n Sometimes the number of rows (names) is unknown ahead

Pointer to Pointer n n Sometimes the number of rows (names) is unknown ahead of time. In this case, we should allocate both the rows as well as the elements of each vector: 1. 2. Allocate array of pointers. Allocate each pointer in the array. ספטמבר 04 Copyright Meir Kalech 26

Pointer to Pointer pp. Char: 100 0 buffer: 900 num: 120 ? char **pp.

Pointer to Pointer pp. Char: 100 0 buffer: 900 num: 120 ? char **pp. Char = NULL, buffer[30]; int num; ? ? ? … ? ספטמבר 04 Copyright Meir Kalech 27

Pointer to Pointer pp. Char: 100 num: 120 150 3 150 0 0 char

Pointer to Pointer pp. Char: 100 num: 120 150 3 150 0 0 char **pp. Char = NULL, buffer[30]; int num; printf(“how many names? ”); scanf(“%d”, &num); pp. Char = (char **) calloc(num, sizeof(char *)); INPUT: 3 0 buffer: 0 0 0 … 0 900 ספטמבר 04 Copyright Meir Kalech 28

Pointer to Pointer pp. Char: 100 num: 120 150 3 150 200 S N

Pointer to Pointer pp. Char: 100 num: 120 150 3 150 200 S N 0 0 O W char **pp. Char = NULL, buffer[30]; int num, i; printf(“how many names? ”); scanf(“%d”, &num); pp. Char = (char **) calloc(num, sizeof(char *)); for(i=0; i<num; i++) { scanf(“%s”, buffer); pp. Char[i] = (char *) malloc(strlen(buffer)+1); strcpy(pp. Char[i], buffer); } buffer: S N O W … 0 900 ספטמבר 04 Copyright Meir Kalech 29

Pointer to Pointer num: 120 pp. Char: 100 3 150 200 340 S N

Pointer to Pointer num: 120 pp. Char: 100 3 150 200 340 S N O W R E D 0 char **pp. Char = NULL, buffer[30]; int num, i; printf(“how many names? ”); scanf(“%d”, &num); pp. Char = (char **) calloc(num, sizeof(char *)); for(i=0; i<num; i++) { scanf(“%s”, buffer); pp. Char[i] = (char *) malloc(strlen(buffer)+1); strcpy(pp. Char[i], buffer); } buffer: R E D ? … 0 900 ספטמבר 04 Copyright Meir Kalech 30

Pointer to Pointer char** pp. Char = NULL, buffer[30]; int num, i; printf(“how many

Pointer to Pointer char** pp. Char = NULL, buffer[30]; int num, i; printf(“how many names? ”); scanf(“%d”, &num); pp. Char = (char **) calloc(num, sizeof(char *)); for(i=0; i<num; i++) { scanf(“%s”, buffer); pp. Char[i] = (char *) malloc(strlen(buffer)+1); strcpy(pp. Char[i], buffer); } num: 120 pp. Char: 100 3 150 200 340 S N O W R E D C I N 490 buffer: 900 C I ספטמבר 04 N D E R E D E L R L E A L L A … ? Copyright Meir Kalech 31

Pointer to Pointer - free for(i=0; i<num; i++) free(pp. Char[i]); num: 120 pp. Char:

Pointer to Pointer - free for(i=0; i<num; i++) free(pp. Char[i]); num: 120 pp. Char: 100 3 150 200 340 490 buffer: 900 C I ספטמבר 04 N D S N O W R E D C I N E R E D E L R L E A L L A … ? Copyright Meir Kalech 32

Pointer to Pointer - free for(i=0; i<num; i++) free(pp. Char[i]); num: 120 pp. Char:

Pointer to Pointer - free for(i=0; i<num; i++) free(pp. Char[i]); num: 120 pp. Char: 100 3 150 200 340 490 buffer: 900 C I ספטמבר 04 N D E R E L L A … ? Copyright Meir Kalech 33

Pointer to Pointer - free pp. Char: 100 num: 120 150 buffer: 900 for(i=0;

Pointer to Pointer - free pp. Char: 100 num: 120 150 buffer: 900 for(i=0; i<num; i++) free(pp. Char[i]); free(pp. Char); 3 C I ספטמבר 04 N D E R E L L A … ? Copyright Meir Kalech 34

Dynamic Memory Allocation - Function n n How to allocate memory in a function?

Dynamic Memory Allocation - Function n n How to allocate memory in a function? Problem: indeed DMA lifetime does not depend on the function, but the scope and lifetime of the pointer to the memory is only in the function! So how to use the allocated memory also outside the function? Solution: n n Return the pointer from the function. Pass the pointer by address. ספטמבר 04 Copyright Meir Kalech 35

Problem void func() HEAP: { int *p; 100 p = (int *) calloc(3, sizeof(int));

Problem void func() HEAP: { int *p; 100 p = (int *) calloc(3, sizeof(int)); 0 } void main() { func(); // how to use p here? ? ? STACK: } 0 0 main ספטמבר 04 Copyright Meir Kalech 36

Return Address int *func() HEAP: { int *p; 100 p = (int *) calloc(3,

Return Address int *func() HEAP: { int *p; 100 p = (int *) calloc(3, sizeof(int)); 0 return p; } void main() { int *pm = func(); STACK: } 0 0 main pm: 250 100 ספטמבר 04 Copyright Meir Kalech 37

Pass Address void func(int *p) HEAP: { p = (int *) calloc(3, sizeof(int)); }

Pass Address void func(int *p) HEAP: { p = (int *) calloc(3, sizeof(int)); } void main() { int* pm = NULL; func(pm); // how to use p here? ? ? STACK: } main pm: 250 ספטמבר 04 Copyright Meir Kalech 0 38

Pass Address HEAP: void func(int *p) { p = (int *) calloc(3, sizeof(int)); }

Pass Address HEAP: void func(int *p) { p = (int *) calloc(3, sizeof(int)); } void main() { int *pm = NULL; func(pm); // how to use p here? ? ? STACK: } main pm: 250 0 func p: 400 ספטמבר 04 Copyright Meir Kalech 0 39

Pass Address void func(int *p) HEAP: { 100 p = (int *) calloc(3, sizeof(int));

Pass Address void func(int *p) HEAP: { 100 p = (int *) calloc(3, sizeof(int)); } 0 void main() { int *pm = NULL; func(pm); } 0 0 STACK: main pm: 250 0 func p: 400 ספטמבר 04 Copyright Meir Kalech 100 40

Pass Address – Right Way void func(int **p) HEAP: { *p = (int *)

Pass Address – Right Way void func(int **p) HEAP: { *p = (int *) calloc(3, sizeof(int)); } void main() { int *pm = NULL; func(&pm); } STACK: main pm: 250 0 func p: 400 ספטמבר 04 Copyright Meir Kalech 250 41

Pass Address – Right Way void func(int **p) HEAP: { 100 *p = (int

Pass Address – Right Way void func(int **p) HEAP: { 100 *p = (int *) calloc(3, sizeof(int)); } 0 void main() { int *pm = NULL; func(&pm); } 0 0 STACK: If a parameter (pointer) is changed in a function (“p =“), it must be passed by address. If its pointed value is changed (“p[i] =“), it can be passed by value. ספטמבר 04 Copyright Meir Kalech main pm: 250 100 func p: 400 250 42