Download presentation
Presentation is loading. Please wait.
Published byRonald Reynolds Modified over 6 years ago
1
Memory Management in C Notes courtesy of Dr. D. Rothe, modified by Dr. R. Hasker
2
Calling Functions Why have a stack?
Executing a program: executing threads Each thread == stack Why have a stack? Local variables must be stored in “temporary” memory, and not at a fixed address: No point in allocating memory until it is needed What if the same function is called more than once – recursion? If a function is finished and never will be called again, why not reuse memory? Most processors have built-in stack management
3
Setting up stack for main Assumption: stack grows down
/* code35.c stack example */ #include <stdio.h> int function1(int a, int b); short function2(short a, char b); int main() { int a; int b = 10; a = 20; b = function1( a , b ); a = function2( 100 , b ); printf( "value: %d\n", a ); return 0; } int function1(int a, int b) int c = a * b; return c; short function2(short a, char b) Address Contents Description FP SP PC FP-1 ???? main:a FP-2 10 main:b FP Setting up stack for main Assumption: stack grows down Initially: stack pointer at top At end: SP <- SP + 2
4
Address Contents Description FP PC FP-1 20 main:a FP-2 10 main:b
/* code35.c stack example */ #include <stdio.h> int function1(int a, int b); short function2(short a, char b); int main() { int a; int b = 10; a = 20; b = function1( a , b ); a = function2( 100 , b ); printf( "value: %d\n", a ); return 0; } int function1(int a, int b) int c = a * b; return c; short function2(short a, char b) Address Contents Description FP PC FP-1 20 main:a FP-2 10 main:b Address Contents Description X (from SP) 20 main:a X-1 10 main:b
5
Will use R0, R1 to transfer data to function1 Register Contents R0 20
/* code35.c stack example */ #include <stdio.h> int function1(int a, int b); short function2(short a, char b); int main() { int a; int b = 10; a = 20; b = function1( a , b ); a = function2( 100 , b ); printf( "value: %d\n", a ); return 0; } int function1(int a, int b) int c = a * b; return c; short function2(short a, char b) Address Contents Description X (from SP) 20 main:a X-1 10 main:b Address Contents Description FP PC FP-1 20 main:a FP-2 10 main:b Call function1… Will use R0, R1 to transfer data to function1 Register Contents R0 20 R1 10
6
Copying to parameters a, b Register Contents R0 20 R1 10
/* code35.c stack example */ #include <stdio.h> int function1(int a, int b); short function2(short a, char b); int main() { int a; int b = 10; a = 20; b = function1( a , b ); a = function2( 100 , b ); printf( "value: %d\n", a ); return 0; } int function1(int a, int b) int c = a * b; return c; short function2(short a, char b) Address Contents Description FP PC FP-1 20 main:a FP-2 10 main:b FP SP func1:a func1:b FP-3 200 func1:c Address Contents Description X (from SP) 20 main:a X-1 10 main:b Copying to parameters a, b Register Contents R0 20 R1 10
7
RET (PC pop from stack) FP pop from stack Register Contents R0 200
/* code35.c stack example */ #include <stdio.h> int function1(int a, int b); short function2(short a, char b); int main() { int a; int b = 10; a = 20; b = function1( a , b ); a = function2( 100 , b ); printf( "value: %d\n", a ); return 0; } int function1(int a, int b) int c = a * b; return c; short function2(short a, char b) Address Contents Description FP PC FP-1 20 main:a FP-2 10 main:b func1:a func1:b FP-3 200 func1:c Address Contents Description X (from SP) 20 main:a X-1 10 main:b Return: SP FP RET (PC pop from stack) FP pop from stack Register Contents R0 200 R1 10
8
Address Contents Description FP PC FP-1 20 main:a FP-2 200 main:b
/* code35.c stack example */ #include <stdio.h> int function1(int a, int b); short function2(short a, char b); int main() { int a; int b = 10; a = 20; b = function1( a , b ); a = function2( 100 , b ); printf( "value: %d\n", a ); return 0; } int function1(int a, int b) int c = a * b; return c; short function2(short a, char b) Address Contents Description FP PC FP-1 20 main:a FP-2 200 main:b func1:a 10 func1:b FP-3 func1:c Address Contents Description X (from SP) 20 main:a X-1 10 main:b Register Contents R0 200 R1 10
9
Calling a function that takes pointers as arguments.
/* code36.c pointer example */ #include <stdio.h> void swap(int *a, int *b); int main() { int a = 5; int b = 10; swap( &a, &b ); printf("a:%d,b:%d\n",a,b); return 0; } void swap(int *x, int *y) int temp = *x; *x = *y; *y = temp; return; Address Contents Description 0x1234 PC 0x1233 5 main:a 0x1232 10 main:b Calling a function that takes pointers as arguments. Assumption: addresses given as words
10
Copy addresses, not values, to R0 and R1 Register Contents R0 0x1233
/* code36.c pointer example */ #include <stdio.h> void swap(int *a, int *b); int main() { int a = 5; int b = 10; swap( &a, &b ); printf("a:%d,b:%d\n",a,b); return 0; } void swap(int *x, int *y) int temp = *x; *x = *y; *y = temp; return; Address Contents Description 0x1234 PC 0x1233 5 main:a 0x1232 10 main:b Copy addresses, not values, to R0 and R1 Register Contents R0 0x1233 R1 0x1232
11
Address Contents Description 0x1234 PC 0x1233 5 main:a 0x1232 10
/* code36.c pointer example */ #include <stdio.h> void swap(int *a, int *b); int main() { int a = 5; int b = 10; swap( &a, &b ); printf("a:%d,b:%d\n",a,b); return 0; } void swap(int *x, int *y) int temp = *x; *x = *y; *y = temp; return; Address Contents Description 0x1234 PC 0x1233 5 main:a 0x1232 10 main:b 0x1231 FP 0x1230 0x122F swap:*x 0x122E swap:*y 0x122D ???? swap:temp Register Contents R0 0x1233 R1 0x1232
12
Address Contents Description 0x1234 PC 0x1233 5 main:a 0x1232 10
/* code36.c pointer example */ #include <stdio.h> void swap(int *a, int *b); int main() { int a = 5; int b = 10; swap( &a, &b ); printf("a:%d,b:%d\n",a,b); return 0; } void swap(int *x, int *y) int temp = *x; *x = *y; *y = temp; return; Address Contents Description 0x1234 PC 0x1233 5 main:a 0x1232 10 main:b 0x1231 FP 0x1230 0x122F swap:*x 0x122E swap:*y 0x122D swap:temp
13
Address Contents Description 0x1234 PC 0x1233 10 main:a 0x1232 main:b
/* code36.c pointer example */ #include <stdio.h> void swap(int *a, int *b); int main() { int a = 5; int b = 10; swap( &a, &b ); printf("a:%d,b:%d\n",a,b); return 0; } void swap(int *x, int *y) int temp = *x; *x = *y; *y = temp; return; Address Contents Description 0x1234 PC 0x1233 10 main:a 0x1232 main:b 0x1231 FP 0x1230 0x122F swap:*x 0x122E swap:*y 0x122D 5 swap:temp
14
Address Contents Description 0x1234 PC 0x1233 10 main:a 0x1232 5
/* code36.c pointer example */ #include <stdio.h> void swap(int *a, int *b); int main() { int a = 5; int b = 10; swap( &a, &b ); printf("a:%d,b:%d\n",a,b); return 0; } void swap(int *x, int *y) int temp = *x; *x = *y; *y = temp; return; Address Contents Description 0x1234 PC 0x1233 10 main:a 0x1232 5 main:b 0x1231 FP 0x1230 0x122F swap:*x 0x122E swap:*y 0x122D swap:temp
15
Values of a, b now exchanged.
/* code36.c pointer example */ #include <stdio.h> void swap(int *a, int *b); int main() { int a = 5; int b = 10; swap( &a, &b ); printf("a:%d,b:%d\n",a,b); return 0; } void swap(int *x, int *y) int temp = *x; *x = *y; *y = temp; return; Address Contents Description 0x1234 PC 0x1233 10 main:a 0x1232 5 main:b 0x1231 FP 0x1230 0x122F swap:*x 0x122E swap:*y 0x122D swap:temp Values of a, b now exchanged.
16
Arrays vs. pointers on the stack
/* code20.c char arrays */ #include <stdio.h> int main() { char a[10]; char b[] = "Hello"; a[0] = 'a'; a[1] = 77; printf("a[0]: %c\n",a[0]); printf("a[1] char: %c\n",a[1]); printf("a[1] int: %d\n",a[1]); printf("a[10]: %c\n",a[10]); printf("b: %s\n",b); printf("b[0]: %c\n",b[0]); printf("b[1]: %c\n",b[1]); printf("sizeof a: %lu\n",sizeof(a)); printf("sizeof b: %lu\n",sizeof(b)); return 0; } /* code23.c pointers */ #include <stdio.h> int main() { char a[10]; char *b = "Hello"; a[0] = 'a'; a[1] = 77; printf("a[0]: %c\n",a[0]); printf("a[1] char: %c\n",a[1]); printf("a[1] int: %d\n",a[1]); printf("a[10]: %c\n",a[10]); printf("b: %s\n",b); printf("b[0]: %c\n",b[0]); printf("b[1]: %c\n",b[1]); printf("sizeof a: %lu\n",sizeof(a)); printf("sizeof b: %lu\n",sizeof(b)); return 0; } Almost the same…well not really, but can be used in similar fashion (below) Arrays vs. pointers on the stack
17
Arrays vs. pointers on the stack
/* code20.c char arrays */ #include <stdio.h> int main() { char a[10]; char b[] = "Hello"; a[0] = 'a'; a[1] = 77; printf("a[0]: %c\n",a[0]); printf("a[1] char: %c\n",a[1]); printf("a[1] int: %d\n",a[1]); printf("a[10]: %c\n",a[10]); printf("b: %s\n",b); printf("b[0]: %c\n",b[0]); printf("b[1]: %c\n",b[1]); printf("sizeof a: %lu\n",sizeof(a)); printf("sizeof b: %lu\n",sizeof(b)); return 0; } /* code23.c pointers */ #include <stdio.h> int main() { char a[10]; char *b = "Hello"; a[0] = 'a'; a[1] = 77; printf("a[0]: %c\n",a[0]); printf("a[1] char: %c\n",a[1]); printf("a[1] int: %d\n",a[1]); printf("a[10]: %c\n",a[10]); printf("b: %s\n",b); printf("b[0]: %c\n",b[0]); printf("b[1]: %c\n",b[1]); printf("sizeof a: %lu\n",sizeof(a)); printf("sizeof b: %lu\n",sizeof(b)); return 0; } Almost the same…well not really, but can be used in similar fashion (below) Arrays vs. pointers on the stack b is a char pointer and that pointer is located on the stack. B can be made to point to any location in memory and when dereferenced, will treat the contents of that memory as characters. B is initialized to point to a location in .rodata that holds the characters Hello<null>. If b is indexed, characters can be read from .rodata, but not written. b is an array allocated on the stack. The characters H,e,l,l,o, and null are placed on the stack programmatically when the function starts. When b is used without brackets, it is a char* pointing to the first position in the array. The contents of the array can be changed. Although b is treated as a char*, it can never be made to point anywhere but the stack location of the array.
18
Memory Segments The stack is used for local variables (auto storage class) What about data that… Needs global access? Needs a persistent value / location? Size is not known or changes during runtime? What about all of those string literals?
19
Typical Memory Layout Code Segment “text” the code
stack grows down | | | | \/\/\/\/ /\/\/\/\ heap allocates up bss (fixed) data (fixed) rodata (fixed) text (fixed) Typical Memory Layout Code Segment “text” the code “rodata” read-only data, constants and string literals Data Segment “data” initialized global and static variables “bss” global and static variables with 0 default heap available for dynamic allocation stack locals (automatic) variables
20
Dynamic Memory – just throw it on the heap
Necessary for data with size unknown at compile time Necessary when a function needs to make (new) data available to a caller back to the standard library
21
void* malloc(size_t size);
#include <stdlib.h> void* malloc(size_t size); void free(void* ptr); void* calloc(size_t nmemb, size_t size); void* realloc(void* ptr, size_t size); size_t: implementation-dependent integer for sizes typedef, sized to support largest possible array often unsigned long void*: a pointer with no implicit dereference interpretation Can be assigned or cast to an appropriate pointer type malloc: memory allocation, data not initialized calloc: allocate array, memory set to all 0s realloc: extend or move existing data
22
void* malloc(size_t size);
#include <stdlib.h> void* malloc(size_t size); void free(void* ptr); void* calloc(size_t nmemb, size_t size); void* realloc(void* ptr, size_t size); size_t: implementation-dependent integer for sizes typedef, sized to support largest possible array often unsigned long void*: a pointer with no implicit dereference interpretation Can be assigned or cast to an appropriate pointer type
23
void* malloc(size_t size);
#include <stdlib.h> void* malloc(size_t size); void free(void* ptr); void* calloc(size_t nmemb, size_t size); void* realloc(void* ptr, size_t size); size_t: implementation-dependent integer for sizes typedef, sized to support largest possible array often unsigned long void*: a pointer with no implicit dereference interpretation Can be assigned or cast to an appropriate pointer type Legal in C: int nums[100]; void *p = nums; int *alias = p; char *oops = p;
24
void* malloc(size_t size);
#include <stdlib.h> void* malloc(size_t size); void free(void* ptr); void* calloc(size_t nmemb, size_t size); void* realloc(void* ptr, size_t size); size_t: implementation-dependent integer for sizes typedef, sized to support largest possible array often unsigned long void*: a pointer with no implicit dereference interpretation Can be assigned or cast to an appropriate pointer type Legal in C: int nums[100]; void *p = nums; int *alias = p; char *oops = p; Not legal in C++
25
/* using malloc */ #include <stdio.h> #include <stdlib.h> int main() { // make a dynamic integer int *a = malloc(sizeof(int)); // use it *a = 57; printf("myint: %d is at %p\n", *a, a); // get rid of it free(a); return 0; }
26
#include <stdio.h> #include <stdlib.h> int main() {
/* using malloc */ #include <stdio.h> #include <stdlib.h> int main() { // make a dynamic integer int *a = malloc(sizeof(int)); // use it *a = 57; printf("myint: %d is at %p\n", *a, a); // get rid of it free(a); return 0; } Output: myint: 57 is at B0
27
/* malloc with error checking */
#include <stdio.h> #include <stdlib.h> int main() { // make a dynamic integer int *a; a = malloc(sizeof(int)); // a will be NULL (stdlib, stdio) if malloc failed if (a == NULL) puts("malloc failed\n"); exit(EXIT_FAILURE); } // use it *a = 57; printf("myint: %d is at %p\n", *a , a ); // get rid of it free(a); return 0;
28
/* array and malloc */ #include <stdio.h> #include <stdlib.h> int main() { // make a dynamic integer int *a; // what if we want many? a = malloc(sizeof(int) * 100); // use it with "pointer arithmetic" *a = 57; // <-- first int *(a + 1) = 87; // <-- second int // use it as an array printf("myint 0: %d is at %p\n", a[0], &a[0]); printf("myint 1: %d is at %p\n", a[1], &a[1]); // get rid of it free(a); return 0; }
29
/* array and malloc */ #include <stdio.h> #include <stdlib.h> int main() { // make a dynamic integer int *a; // what if we want many? a = malloc(sizeof(int) * 100); // use it with "pointer arithmetic" *a = 57; // <-- first int *(a + 1) = 87; // <-- second int // use it as an array printf("myint 0: %d is at %p\n", a[0], &a[0]); printf("myint 1: %d is at %p\n", a[1], &a[1]); // get rid of it free(a); return 0; } Output: myint 0: 57 is at B113B0 myint 1: 87 is at B113B4
30
What’s the output of printf("%d", *a + 1); /* array and malloc */
#include <stdio.h> #include <stdlib.h> int main() { // make a dynamic integer int *a; // what if we want many? a = malloc(sizeof(int) * 100); // use it with "pointer arithmetic" *a = 57; // <-- first int *(a + 1) = 87; // <-- second int // use it as an array printf("myint 0: %d is at %p\n", a[0], &a[0]); printf("myint 1: %d is at %p\n", a[1], &a[1]); // get rid of it free(a); return 0; } What’s the output of printf("%d", *a + 1);
31
/* realloc */ #include <stdio.h> #include <stdlib.h> int main() { // make a dynamic integer int *a, *b; // what if we want many? a = malloc(sizeof(int) * 100); b = malloc(sizeof(int)); // where are they? printf("a: %p\n", a); printf("b: %p\n", b); // realloc a a = realloc(a, sizeof(int) * 200); printf("a: %p\n",a); printf("b: %p\n",b); // get rid of it free(a); free(b); return 0; }
32
/* realloc */ #include <stdio.h> #include <stdlib.h> int main() { // make a dynamic integer int *a, *b; // what if we want many? a = malloc(sizeof(int) * 100); b = malloc(sizeof(int)); // where are they? printf("a: %p\n", a); printf("b: %p\n", b); // realloc a a = realloc(a, sizeof(int) * 200); printf("a: %p\n",a); printf("b: %p\n",b); // get rid of it free(a); free(b); return 0; } Output: a: C613B0 b: C61550 a: C61570
33
If comment out this line:
/* realloc */ #include <stdio.h> #include <stdlib.h> int main() { // make a dynamic integer int *a, *b; // what if we want many? a = malloc(sizeof(int) * 100); b = malloc(sizeof(int)); // where are they? printf("a: %p\n", a); printf("b: %p\n", b); // realloc a a = realloc(a, sizeof(int) * 200); printf("a: %p\n",a); printf("b: %p\n",b); // get rid of it free(a); free(b); return 0; } Output: a: C613B0 b: C61550 a: C61570 If comment out this line: a: B0 b:
34
Warning: dangerouscode!
/* returning malloc string */ #include <stdio.h> #include <stdlib.h> #include <string.h> // get day of week string – user expects to modify!!! char *dayString(int day) { // allocate dynamically char* ds = malloc(10*sizeof(char)); switch(day) case 0: strcpy(ds, "Sunday"); break; case 1: strcpy(ds, "Monday"); default: strcpy(ds, "other"); } return ds; int main() printf("Day: %s\n", dayString(0)); printf("Day: %s\n", dayString(1)); printf("Day: %s\n", dayString(2)); return 0; Warning: dangerouscode! Output: Day: Sunday Day: Monday Day: other Issue: memory leak!
35
for(int i = 0; i < 1000; ++i) days[i] = dayString(I % 3);
/* returning malloc string */ #include <stdio.h> #include <stdlib.h> #include <string.h> // get day of week string – user expects to modify!!! char *dayString(int day) { // allocate dynamically char* ds = malloc(10*sizeof(char)); switch(day) case 0: strcpy(ds, "Sunday"); break; case 1: strcpy(ds, "Monday"); default: strcpy(ds, "other"); } return ds; int main() printf("Day: %s\n", dayString(0)); printf("Day: %s\n", dayString(1)); printf("Day: %s\n", dayString(2)); return 0; Warning: dangerouscode! Output: Day: Sunday Day: Monday Day: other Consider: char *days[1000]; for(int i = 0; i < 1000; ++i) days[i] = dayString(I % 3); Issue: memory leak!
36
Improved – no memory leak Is there a better solution?
/* removing the leak */ #include <stdio.h> #include <stdlib.h> #include <string.h> // get day of week string char* dayString(char* ds, int day) { switch(day) case 0: strcpy(ds, "Sunday"); break; case 1: strcpy(ds, "Monday"); default: strcpy(ds, "other"); } return ds; int main() char day[10]; dayString(day, 0); printf("Day: %s\n", day); printf("Day: %s\n", dayString(day, 1)); return 0; Improved – no memory leak Is there a better solution?
37
char* dayString(int day) { char ds[10]; switch(day) case 0:
/* removing the leak */ #include <stdio.h> #include <stdlib.h> #include <string.h> // get day of week string char* dayString(char* ds, int day) { switch(day) case 0: strcpy(ds, "Sunday"); break; case 1: strcpy(ds, "Monday"); default: strcpy(ds, "other"); } return ds; int main() char day[10]; dayString(day, 0); printf("Day: %s\n", day); printf("Day: %s\n", dayString(day, 1)); return 0; How about this? char* dayString(int day) { char ds[10]; switch(day) case 0: strcpy(ds, "Sunday"); break; case 1: strcpy(ds, "Monday"); default: strcpy(ds, "other"); } return ds;
38
char* dayString(int day) { char ds[10]; switch(day) case 0:
/* removing the leak */ #include <stdio.h> #include <stdlib.h> #include <string.h> // get day of week string char* dayString(char* ds, int day) { switch(day) case 0: strcpy(ds, "Sunday"); break; case 1: strcpy(ds, "Monday"); default: strcpy(ds, "other"); } return ds; int main() char day[10]; dayString(day, 0); printf("Day: %s\n", day); printf("Day: %s\n", dayString(day, 1)); return 0; How about this? char* dayString(int day) { char ds[10]; switch(day) case 0: strcpy(ds, "Sunday"); break; case 1: strcpy(ds, "Monday"); default: strcpy(ds, "other"); } return ds; int main() { char* d = dayString(0); printf("Day: %s\n", d); printf(“Try again: %s\n", d); printf(“Day: %s\n”, dayString(1)); return 0; } Output: Day: (null) Try again: (null)
39
Copying arrays Simple solution: Using memcpy: Avoids coding errors
Possibly more efficient for non-word sizes Danger: destination cannot overlap source int xs[100], ys[100]; … for(int i = 0; i < 100; ++i) xs[i] = ys[i]; #include <string.h> int xs[100], ys[100]; … memcpy(xs, ys, 100 * sizeof(*ys));
40
Copying arrays With structures: #include <string.h>
typedef struct { int a, b; } Point; Point line1[100], line2[100]; … memcpy(line1, line2, 100 * sizeof(*line2));
41
Review Functions & local (stack-based) data
Program memory layout (C, C++) Heap, stack, bss Also: text (code) Differences between int x[]; and int *x; malloc, free calloc, realloc memcpy
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.