Memory Arrangement Memory is arrange in a sequence

  • Slides: 48
Download presentation
Memory Arrangement • Memory is arrange in a sequence of addressable units (usually bytes)

Memory Arrangement • Memory is arrange in a sequence of addressable units (usually bytes) – sizeof( <Type> ) return the number of units it takes to store a type. – sizeof(char) = 1 – sizeof(int) = 4 (on most of our machines)

Memory int main() { char c; int i, j; double x; … c i

Memory int main() { char c; int i, j; double x; … c i j x

Arrays Defines a block of consecutive cells int main() { int i; int a[4];

Arrays Defines a block of consecutive cells int main() { int i; int a[4]; … i a[0] a[1] a[2] a[3]

Arrays • C does not provide any run time checks int a[4]; a[-1] =

Arrays • C does not provide any run time checks int a[4]; a[-1] = 0; a[4] = 0; This will compile and run (no errors) …but can lead to unpredictable results. • It is the programmer’s responsibility to check whether the index is out of bounds…

Arrays • C does not provide array operations int … a = if( …

Arrays • C does not provide array operations int … a = if( … a[4]; b; // illegal a == b ) // illegal

Array Initialization int int arr[3] arr[4] arr[2] = = {3, {3, 4, 4, 5};

Array Initialization int int arr[3] arr[4] arr[2] = = {3, {3, 4, 4, 5}; 5}; // // Good - The same Good - The last is 0 Bad int arr[2][3] = {{2, 5, 7}, {4, 6, 7}}; // Good int arr[2][3] = {2, 5, 7, 4, 6, 7}; // Good - The same int arr[3][2] = {{2, 5, 7}, {4, 6, 7}}; // Bad int arr[3]; arr = {2, 5, 7}; // Bad - array assignment only in initialization

Pointers int main() { int i, j; int *x; // x points to an

Pointers int main() { int i, j; int *x; // x points to an integer i = 1; x = &i; j = *x; x = &j; (*x) = 3; i j x 1

Pointers int main() { int i, j; int *x; // x points to an

Pointers int main() { int i, j; int *x; // x points to an integer i = 1; x = &i; j = *x; x = &j; (*x) = 3; i j x 1 0 x 0100

Pointers int main() { int i, j; int *x; // x points to an

Pointers int main() { int i, j; int *x; // x points to an integer i = 1; x = &i; j = *x; x = &j; (*x) = 3; i j x 1 0 x 0100

Pointers int main() { int i, j; int *x; // x points to an

Pointers int main() { int i, j; int *x; // x points to an integer i = 1; x = &i; j = *x; x = &j; (*x) = 3; i j x 1 0 x 0100 1 0 x 0104

Pointers int main() { int i, j; int *x; // x points to an

Pointers int main() { int i, j; int *x; // x points to an integer i = 1; x = &i; j = *x; x = &j; (*x) = 3; i j x 1 0 x 0100 3 0 x 0104

Pointers • Declaration <type> *p; p points to objects of type <type> • Reference

Pointers • Declaration <type> *p; p points to objects of type <type> • Reference &x - the pointer to x • De. Reference *p = x; y = *p; *p refers to the object p points to

Example – the swap function Does nothing void swap(int a, int b) { int

Example – the swap function Does nothing void swap(int a, int b) { int temp = a; a = b; b = temp; } …. int main() { int x, y; x = 3; y = 7; swap(x, y); // now x==3, y==7 …. Works void swap(int *pa, int *pb) { int temp = *pa; *pa = *pb; *pb = temp; } …. int main() { int x, y; x = 3; y = 7; swap(&x, &y); // x == 7, y == 3 …

Pointers & Arrays int *p; int a[4]; p = &a[0]; *(p+1) = 1; //

Pointers & Arrays int *p; int a[4]; p = &a[0]; *(p+1) = 1; // assignment to a[1]! p a[0] a[1] a[2] a[3]

Pointers & arrays Arrays are essentially constant pointers int *p; int a[4]; p =

Pointers & arrays Arrays are essentially constant pointers int *p; int a[4]; p = a; // same as p = &a[0] p[1] = 102; // same as *(p+1)=102; *(a+1) = 102; // same p++; // p == a+1 == &a[1] a = p; // illegal a++; // illegal

Pointers & Arrays int foo( int *p ); and int foo( int a[] );

Pointers & Arrays int foo( int *p ); and int foo( int a[] ); Are declaring the same interface • In both cases, a pointer to int is being passed to the function foo

Pointer Arithmetic int a[4]; int *p = a; char *q = (char *)a; //

Pointer Arithmetic int a[4]; int *p = a; char *q = (char *)a; // Explicit cast // p and q point to the same location p++; // increment p by 1 int (4 bytes) q++; // increment q by 1 char (1 byte) a[0] q a[1] p a[2] a[3]

Pointer arithmetic int Find. First. Non. Zero( int a[], int n ) { int

Pointer arithmetic int Find. First. Non. Zero( int a[], int n ) { int *p; for( p = a; (p < a+n) && ((*p) == 0); p++ ) ; return p-a; } Same as int Find. First. Non. Zero( int a[], int n ) { int i; for( i = 0; (i < n) && (a[i] == 0); i++ ) ; return i; }

void *p defines a pointer to undetermined type int j; int *p = &j;

void *p defines a pointer to undetermined type int j; int *p = &j; void* q = p; // no cast needed p = (int*)q ; // cast is needed

NULL pointer • Special value: uninitialized pointer int *p = NULL; … if( p

NULL pointer • Special value: uninitialized pointer int *p = NULL; … if( p != NULL ) { … }

Strings in C

Strings in C

C String char: usually 1 byte. An Integer (ASCII code). String: An array of

C String char: usually 1 byte. An Integer (ASCII code). String: An array of characters. char* txt 1 = “text”; char txt 2[] = “text”; char txt 3[] = {‘t’, ’e’, ’x’, ’t’, ’’}; t e x t

C Strings • Strings are always terminated by a null character, (a character with

C Strings • Strings are always terminated by a null character, (a character with integer value 0 equals to the special character ‘’). • There is no way to enforce it when you do your own strings →: – Remember it’s there – Allocate memory for it

C String Example char* text = “string”; // means text[5] == ‘g’ and text[6]

C String Example char* text = “string”; // means text[5] == ‘g’ and text[6] == ‘’ // 7 chars are allocated!

C Strings More Examples • Recall arrays are essentially constant pointers. char txt 1[]

C Strings More Examples • Recall arrays are essentially constant pointers. char txt 1[] = “text”; char* txt 2 = “text”; int i = strlen(txt 1); // i = 4, same for strlen(txt 2); txt 1[0] = ‘n’; //”next”; txt 1 = txt 2; // illegal ! txt 2 = txt 1; //legal. now txt 2 points to the same string.

C Strings Manipulation • To manipulate a single character use the functions defined in

C Strings Manipulation • To manipulate a single character use the functions defined in ctype. h #include <ctype. h> • Manipulation of Strings is done by including the string. h header file #include <string. h> • Read manual pages: string and isalpha

Test yourself • What does this do? What are the assumptions ? int f(const

Test yourself • What does this do? What are the assumptions ? int f(const char * p, const char * q) { for(; *p && *p ==*q; p++, q++) ; return *p-*q; }

Memory Organization • During run time, variables can be stored in one of three

Memory Organization • During run time, variables can be stored in one of three “pools” – Stack – Static heap – Dynamic heap

Stack • Maintains memory during function calls – Argument of the function – Local

Stack • Maintains memory during function calls – Argument of the function – Local variables – Call Frame • Variables on the stack have limited “life time”

Stack - Example int foo( int a, double f ) { int b; …

Stack - Example int foo( int a, double f ) { int b; … } <call> a f b

Stack - Example int foo( int a, double f ) { int b; …

Stack - Example int foo( int a, double f ) { int b; … { int c; … } <call> a f b

Stack - Example int foo( int a, double f ) { int b; …

Stack - Example int foo( int a, double f ) { int b; … { int c; … } <call> a f b c

Stack - Example int foo( int a, double f ) { int b; …

Stack - Example int foo( int a, double f ) { int b; … { int c; … } <call> a f b c

Stack - Example int foo( int a, double f ) { int b; …

Stack - Example int foo( int a, double f ) { int b; … { int c; … } <call> a f b c

Stack – recursive example void foo( int depth ) { int a; if( depth

Stack – recursive example void foo( int depth ) { int a; if( depth > 1 ) foo( depth-1 ); } int main() { foo(3); <call> depth a

Stack – errors? void foo( int depth ) { int a; if( depth >

Stack – errors? void foo( int depth ) { int a; if( depth > 1 ) foo( depth ); } Will result in run time error: out of stack space

Static heap • Memory for global variables #include <stdio. h> const int List. Of.

Static heap • Memory for global variables #include <stdio. h> const int List. Of. Numbers. Size = 1000; int List. Of. Numbers[List. Of. Numbers. Size]; int main() { …

Static heap • Variables on the static heap are defined throughout the execution of

Static heap • Variables on the static heap are defined throughout the execution of the program • Memory on the static heap must be defined at compile time

Static heap: reverse example Example: program to reverse the order of lines of a

Static heap: reverse example Example: program to reverse the order of lines of a file To this task, we need to • read the lines into memory • Print lines in reverse How do we store the lines in memory?

Static heap: reverse example const int Line. Length = 100; const int Number. Of.

Static heap: reverse example const int Line. Length = 100; const int Number. Of. Lines = 10000; char Lines[Number. Of. Lines][Line. Length]; … int main() { int n = Read. Lines(); for( n-- ; n >= 0; n-- ) printf(“%sn”, Lines[n]); }

Static heap: reverse example This solution is problematic: • The program cannot handle files

Static heap: reverse example This solution is problematic: • The program cannot handle files larger than these specified by the compile time choices • If we set Number. Of. Lines to be very large, then the program requires this amount of memory even if we are reversing a short file Want to use memory on “as needed” basis

Dynamic Heap • Memory that can be allocated and freed by the program during

Dynamic Heap • Memory that can be allocated and freed by the program during run time • The program controls how much is allocated and when • Limitations based on run-time situation – Available memory on the computer

Allocating Memory from Heap void *malloc( size_t Size ); • Returns a pointer to

Allocating Memory from Heap void *malloc( size_t Size ); • Returns a pointer to a new memory block of size Size • Returns NULL if it cannot allocate memory of this size

Example: strdup Function to duplicate a string: char * strdup( char const *p )

Example: strdup Function to duplicate a string: char * strdup( char const *p ) { int n = strlen(p); char* q =(char*)malloc(sizeof(char)*(n+1)); if( q != NULL ) strcpy( q, p ); return q; } This function is part of the standard library

Memory Management <call> p q void foo( char const* p ) { char *q

Memory Management <call> p q void foo( char const* p ) { char *q = strdup( p ); // do something with q … The allocated memory remains in use • cannot be reused later on Heap } ‘a’ ‘b’ ‘’

De-allocating memory void free( void *p ); • Returns the memory block pointed by

De-allocating memory void free( void *p ); • Returns the memory block pointed by p to the pool of unused memory • No error checking! – If p was not allocated by malloc, undefined behavior

Example of free void foo( char const* p ) { char *q = strdup(

Example of free void foo( char const* p ) { char *q = strdup( p ); // do something with q free(q); } This version frees the allocated memory

Further Knowledge Read manual page of • malloc • calloc • realloc • free

Further Knowledge Read manual page of • malloc • calloc • realloc • free