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 j x
Arrays
Defines a block of consecutive cellsint 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] = 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[4];
int b[4];
… a = b; // illegal
if( a == b ) // illegal
…
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
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
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
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
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
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
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
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…
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]
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 );
andint 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; // 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
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;
}
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
NULL pointer
• Special value: uninitialized pointer
int *p = NULL;
…
if( p != NULL )
{
…
}
Strings in C
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
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
C String Example
char* text = “string”;
// means text[5] == ‘g’ and text[6] == ‘\0’
// 7 chars are allocated!
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.
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 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 “pools”– Stack– Static heap– Dynamic heap
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;
…
}
afb
<call>
Stack - Example
int foo( int a, double f )
{
int b;
…
{
int c;
…
}
…
}
afb
<call>
Stack - Example
int foo( int a, double f )
{
int b;
…
{
int c;
…
}
…
}
afbc
<call>
Stack - Example
int foo( int a, double f )
{
int b;
…
{
int c;
…
}
…
}
afb
<call>
c
Stack - Example
int foo( int a, double f )
{
int b;
…
{
int c;
…
}
…
}
afbc
<call>
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>
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 ListOfNumbersSize = 1000;
int ListOfNumbers[ListOfNumbersSize];
int main()
{
…
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 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 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]);
}
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
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 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 ){ 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
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’
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( p );
// do something with q
free(q);
}
This version frees the allocated memory
Further Knowledge
Read manual page of
• malloc
• calloc
• realloc
• free