memory arrangement memory is arrange in a sequence of addressable units (usually bytes) –sizeof( )...

48
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)

Post on 20-Dec-2015

216 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

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)

Page 2: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Memory

int main()

{

char c;

int i,j;

double x;

c i j x

Page 3: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Arrays

Defines a block of consecutive cellsint main()

{

int i;

int a[4];

i a[0] a[1] a[2] a[3]

Page 4: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

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…

Page 5: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Arrays

• C does not provide array operations int a[4];

int b[4];

… a = b; // illegal

if( a == b ) // illegal

Page 6: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Array Initialization

int arr[3] = {3, 4, 5}; // Good

int arr[] = {3, 4, 5}; // Good - The same

int arr[4] = {3, 4, 5}; // Good - The last is 0

int arr[2] = {3, 4, 5}; // 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

Page 7: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Pointersint 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

Page 8: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Pointersint main()

{

int i,j;

int *x; // x points to an integer

i = 1;

x = &i;

j = *x;

x = &j;

(*x) = 3;i j x

10x0100

0x0100

Page 9: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Pointersint main()

{

int i,j;

int *x; // x points to an integer

i = 1;

x = &i;

j = *x;

x = &j;

(*x) = 3;i j x

10x0100

0x01001

Page 10: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Pointersint main()

{

int i,j;

int *x; // x points to an integer

i = 1;

x = &i;

j = *x;

x = &j;

(*x) = 3;i j x

10x0100

0x01041

Page 11: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Pointersint main()

{

int i,j;

int *x; // x points to an integer

i = 1;

x = &i;

j = *x;

x = &j;

(*x) = 3;i j x

10x0100

0x01043

Page 12: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Pointers• Declaration

<type> *p;

p points to objects of type <type>

• Reference&x - the pointer to x

• DeReference*p = x;

y = *p;

*p refers to the object p points to

Page 13: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Example – the swap functionDoes nothing Works

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….

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…

Page 14: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Pointers & Arrays

int *p;

int a[4];

p = &a[0];

*(p+1) = 1; // assignment to a[1]!

p a[1] a[2] a[3]a[0]

Page 15: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

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

Page 16: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Pointers & Arrays

int foo( int *p );

andint foo( int a[] );

Are declaring the same interface

• In both cases, a pointer to int is being passed to the function foo

Page 17: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

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[1] a[2] a[3]a[0]

q p

Page 18: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Pointer arithmeticint FindFirstNonZero( int a[], int n )

{

int *p;

for( p = a; (p < a+n) && ((*p) == 0); p++ )

;

return p-a;

}

Same as int FindFirstNonZero( int a[], int n )

{

int i;

for( i = 0; (i < n) && (a[i] == 0); i++ )

;

return i;

}

Page 19: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

void *

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

Page 20: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

NULL pointer

• Special value: uninitialized pointer

int *p = NULL;

if( p != NULL )

{

}

Page 21: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Strings in C

Page 22: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

C String Stringchar:

usually 1 byte. An Integer (ASCII code).

String: An array of characters.char* txt1 = “text”;char txt2[] = “text”;char txt3[] = {‘t’,’e’,’x’,’t’,’\0’};

xet t \0

xet t \0

Page 23: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

C Strings

• Strings are always terminated by a null character, (a character with integer value 0 equals to the special character ‘\0’).

• There is no way to enforce it when you do your own strings →:– Remember it’s there

– Allocate memory for it

Page 24: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

C String Example

char* text = “string”;

// means text[5] == ‘g’ and text[6] == ‘\0’

// 7 chars are allocated!

Page 25: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

C Strings More Examples

• Recall arrays are essentially constant pointers.

char txt1[] = “text”;char* txt2 = “text”;int i = strlen(txt1); // i = 4, same for strlen(txt2);txt1[0] = ‘n’; //”next”;txt1 = txt2; // illegal !txt2 = txt1;

//legal. now txt2 points to the same string.

Page 26: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

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

Page 27: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

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;

}

Page 28: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Memory Organization

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

Page 29: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Stack

• Maintains memory during function calls– Argument of the function– Local variables– Call Frame

• Variables on the stack have limited “life time”

Page 30: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Stack - Example

int foo( int a, double f )

{

int b;

}

afb

<call>

Page 31: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Stack - Example

int foo( int a, double f )

{

int b;

{

int c;

}

}

afb

<call>

Page 32: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Stack - Example

int foo( int a, double f )

{

int b;

{

int c;

}

}

afbc

<call>

Page 33: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Stack - Example

int foo( int a, double f )

{

int b;

{

int c;

}

}

afb

<call>

c

Page 34: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Stack - Example

int foo( int a, double f )

{

int b;

{

int c;

}

}

afbc

<call>

Page 35: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Stack – recursive example

void foo( int depth )

{

int a;

if( depth > 1 )

foo( depth-1 );

}

int main()

{

foo(3);

deptha

<call>

deptha

<call>

deptha

<call>

Page 36: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Stack – errors?

void foo( int depth )

{

int a;

if( depth > 1 )

foo( depth );

}

Will result in run time error:

out of stack space

Page 37: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Static heap

• Memory for global variables

#include <stdio.h>

const int ListOfNumbersSize = 1000;

int ListOfNumbers[ListOfNumbersSize];

int main()

{

Page 38: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

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

Page 39: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

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?

Page 40: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Static heap: reverse example

const int LineLength = 100;

const int NumberOfLines = 10000;

char Lines[NumberOfLines][LineLength];

int main()

{

int n = ReadLines();

for( n-- ; n >= 0; n-- )

printf(“%s\n”, Lines[n]);

}

Page 41: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

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 NumberOfLines 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

Page 42: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

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

Page 43: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

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

Page 44: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

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

Page 45: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Memory Management

voidfoo( char const* p ){ char *q = strdup( p );

// do something with q

}

The allocated memory remains in use• cannot be reused later on

pq

<call>…

Hea

p

‘a’‘b’‘\0’

Page 46: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

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

Page 47: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Example of free

void

foo( char const* p )

{

char *q = strdup( p );

// do something with q

free(q);

}

This version frees the allocated memory

Page 48: Memory Arrangement Memory is arrange in a sequence of addressable units (usually bytes) –sizeof( ) return the number of units it takes to store a type

Further Knowledge

Read manual page of

• malloc

• calloc

• realloc

• free