1. Lecture 3: Variables and Storage
TI1220 2012-2013
Concepts of Programming Languages
Eelco Visser / TU Delft
2. Outline
Messages from the lab
Variables & storage
Copy & reference semantics
Lifetime
Local & heap memory
Memory management
(Memory and pointers in C)
10. A program variable is an abstraction of a
computer memory cell or collection of cells
11. Von Neumann Architecture: stored-program computer in
which an instruction fetch and a data operation cannot occur
at the same time because they share a common bus
http://en.wikipedia.org/wiki/File:Computer_system_bus.svg
13. Storage Cell
unique address
status: allocated or unallocated
content: storable value or undefined
primitive variable 63
‘foo’
composite variable ? undefined
false
unallocated cell
14. storable value: can be
stored in single storage cell
C++: primitive values and pointers
Java: primitive values and pointers to objects
Typically: composite values are not storable
15. simple variable: a variable that may contain a
storable value; occupies a single storage cell
{
?
int n;
C n = 0; 0
n = n + 1;
1
}
terminology: “the content of the storage cell denoted by n” ~ “the value of n”
16. dates
composite variable: a variable
of a composite type, occupies a dates[0] y 2013
group of contiguous cells
m 1
d 31
struct Date {
dates[1] y 2013
int y, m, d;
} C
struct Date today; m 2
today.m = 2;
today.d = 26; d 26
today.y = 2013; today dates[2] y ?
struct Date dates[3]; y 2013 m ?
dates[0].y = 2013;
dates[0].m = 1; m 2 d ?
dates[0].d = 31;
dates[1] = today; d 26
17. total update: updating composite
variable with a new value in a single step
struct Date {
int y, m, d;
}
struct Date today, tomorrow;
C
tomorrow = today;
tomorrow.d = today.d + 1;
selective update: updating single
component of a composite variable
18. static array: array variable whose
index range is fixed at compile-time
float v1[] = {2.0, 3.0, 5.0, 7.0};
float v2[10];
void print_vector(float v[], int n) {
printf("[%3.2f", v[0]);
for(int i = 1; i < n; i++) {
printf(" %3.2f", v[i]);
}
printf("]");
}
print_vector(v1, 4);
print_vector(v2, 10);
C
19. dynamic array: array variable whose index
range is fixed at the time when the array is created
type Vector is array (Integer range <>) of Ada
Float;
v1: Vector(1 .. 4) := (2.0, 3.0, 5.0, 7.0);
v2: Vector(0 .. m) := (0 .. m => 0.0);
procedure print_vector(v: in Vector) is
-- Print the array v in the form "[...]".
begin
put('['); put(v(v'first));
for i in v'first + 1 .. v'last loop
put(' '); put(v(i));
end loop
put(']');
end;
print_vector(v1); print_vector(v2);
20. flexible array: array variable whose index range is
not fixed, may change when new array value is assigned
Java float[] v1 = {2.0, 3.0, 5.0, 7.0};
float[] v2 = {0.0, 0.0, 0.0};
v1 = v2; // changes index range of v1
static void printVector(float[] v) {
System.out.print("[" + v[0]);
for(int i = 1; i < v.length; i++) {
System.out.print(" " + v[i]);
}
System.out.print("]");
}
printVector(v1);
printVector(v2);
22. copy semantics: assignment copies all
components of composite value into
corresponding components of composite variable
C struct Date {
int y, m, d;
}
struct Date dateA = {2013, 2, 31};
struct Date dateB;
dateB = dateA; // copy assignment
struct Date *dateP = malloc(sizeof(struct Date));
struct Date *dateQ = malloc(sizeof(struct Date));
*dateP = dateA; // copy assignment
dateQ = dateP; // reference assignment
draw this
23. class Date {
draw this int y, m, d;
public Date(int y, int m, int d) {
// ...
}
}
Date dateR = new Date(2013, 1, 31);
Date dateS = new Date(2012, 11, 26);
dateS = dateR; // reference assignment
Date dateT = new Date(2013, 4, 9);
dateT = dateR.clone(); // copy assignment
Java
reference semantics: assignment makes
composite variable contain a pointer (or
reference) to the composite value
24. equality test should be consistent
with semantics of assignment
under copy semantics equality test is structural: tests
whether corresponding components of two
composite values are equal
under reference semantics equality test
tests whether the pointers to the two
composite values are equal
26. lifetime of a variable: interval between creation
(allocation) and destruction (deallocation)
global variable: declared for use throughout the
program; lifetime is program’s run-time
local variable: declared within a block, for use only
within that block; lifetime is activation of block
heap variable: can be created and destroyed at any
time during the program’s run-time; arbitrary lifetime
bound by program run-time
persistent variable: lifetime transcends activation
of a program
31. Variable Allocation and Deallocation
• holds value
• needs memory for storage during lifetime
Allocation
• obtain memory for storage of variable value
Deallocation
• give memory back
Error: use deallocated variable
32. Rules for Local Storage
Function call
• memory allocated for all locals
• locals = parameters + local variables
During execution of function
• memory for locals allocated even if
another function is called
Function exit
// Local storage example
• locals are deallocated int Square(int num) {
int result;
• end of scope for locals is reached result = num * num;
return result;
}
33. void Foo(int a) {
// (1) Locals (a, i, scores) allocated when Foo runs
int i;
float scores[100];
// This array of 100 floats is allocated locally.
a = a + 1; // (2) Local storage is used by the computation
for (i = 0; i < a; i++) {
Bar(i + a); // (3) Locals continue to exist undisturbed,
} // even during calls to other functions.
} // (4) The locals are all deallocated when the function exits.
C
34. void X() {
int a = 1;
int b = 2;
// T1
Y(a);
// T3
Y(b);
// T5
}
void Y(int p) {
int q;
q = p + 2;
// T2 (first time through),
// T4 (second time through)
}
Stack Frames
35. Local Memory
Advantages
• Convenient: temporary memory for lifetime of function
• Efficient: fast allocation and deallocation, no waste of space
• Local copies: parameters are pass by value
Disadvantages
• Short lifetime: cannot be used for more permanent storage
• Restricted communication: cannot report back to caller
Synonyms
• “automatic” variables
• stack variables
36. Escaping Locals
// TAB -- The Ampersand Bug function
// Returns a pointer to an int
int* TAB() {
int temp;
return (&temp); // return a pointer to the local int
}
void Victim() {
int* ptr;
ptr = TAB();
*ptr = 42; // Runtime error! The pointee was local to TAB
}
40. int x = 1, y = 2, z[10];
int *ip; /* ip is a pointer to int */
ip = &x; /* ip now points to x */
y = *ip; /* y is now 1 */
*ip = 0; /* x is now 0 */
ip = &z[0]; /* ip now points to z[0] */
*ip = *ip + 10; /* z[0] incremented with 10 */
Dereferencing Pointers
41. Pointers and Arrays int a[10];
int *pa;
pa = &a[0];
x = *pa; // x == a[0]
Pointer Arithmetic
42. #define ALLOCSIZE 10000 /* size of available space */
static char allocbuf[ALLOCSIZE]; /* storage for alloc */
static char *allocp = allocbuf; /* next free position */
char *alloc(int n) /* return pointer to n characters */
{
if (allocbuf + ALLOCSIZE - allocp >= n) { /* it fits */
allocp += n;
return allocp - n; /* old p */
} else
/* not enough room */
Pointer Arithmetic
return 0;
}
void afree(char *p) /* free storage pointed to by p */
{
if (p >= allocbuf && p < allocbuf + ALLOCSIZE)
allocp = p;
}
44. Heap memory = dynamic memory
• allocated at run-time
Advantages
• Lifetime: programmer controls memory allocation,
deallocation
• Size: allocate amount of memory needed at run-time
Disadvantages
• More work: manage the heap
• More bugs: ... under control of programmer ...
46. void Heap1() {
int* intPtr;
// Allocates local pointer local variable (but not its pointee)
// Allocates heap block and stores its pointer in local variable.
// Dereferences the pointer to set the pointee to 42.
intPtr = malloc(sizeof(int));
*intPtr = 42;
// Deallocates heap block making the pointer bad.
// The programmer must remember not to use the pointer
// after the pointee has been deallocated (this is
// why the pointer is shown in gray).
free(intPtr);
}
47. void Heap1() {
int* intPtr;
// Allocates local pointer local variable (but not its pointee)
// Allocates heap block and stores its pointer in local variable.
// Dereferences the pointer to set the pointee to 42.
intPtr = malloc(sizeof(int));
*intPtr = 42;
// Deallocates heap block making the pointer bad.
// The programmer must remember not to use the pointer
// after the pointee has been deallocated (this is
// why the pointer is shown in gray).
free(intPtr);
}
48. void Heap1() {
int* intPtr;
// Allocates local pointer local variable (but not its pointee)
// Allocates heap block and stores its pointer in local variable.
// Dereferences the pointer to set the pointee to 42.
intPtr = malloc(sizeof(int));
*intPtr = 42;
// Deallocates heap block making the pointer bad.
// The programmer must remember not to use the pointer
// after the pointee has been deallocated (this is
// why the pointer is shown in gray).
free(intPtr);
}
49. void Heap1() {
int* intPtr;
// Allocates local pointer local variable (but not its pointee)
// Allocates heap block and stores its pointer in local variable.
// Dereferences the pointer to set the pointee to 42.
intPtr = malloc(sizeof(int));
*intPtr = 42;
// Deallocates heap block making the pointer bad.
// The programmer must remember not to use the pointer
// after the pointee has been deallocated (this is
// why the pointer is shown in gray).
free(intPtr);
}
51. Programming the Heap
Heap
• Area of memory to allocate blocks of memory for program
• Heap manager: manages internals of heap
• Free list: private data structure for heap management
• Heap may get full
• requests for more memory fail
• Allocated block reserved for caller
• location and size fixed
• Deallocation gives block back to heap manager
• deallocated blocks should not be used
52. Memory Management API
void *malloc(size_t n);
// returns a pointer to n bytes of uninitialized storage,
// or NULL if the request cannot be satisfied
void *calloc(size_t n, size_t size);
// returns a pointer to enough free space for
// an array of n objects of the specified size,
// or NULL if the request cannot be satisfied.
// The storage is initialized to zero.
void free(void *ap);
// frees the space pointed to by p, where p was
// originally obtained by a call to malloc or calloc.
int *ip;
ip = (int *) calloc(n, sizeof(int));
// allocated memory should be cast to appropriate type
K&R: a sample implementation
53. void HeapArray() {
struct fraction* fracts;
int i;
// allocate the array
fracts = malloc(sizeof(struct fraction) * 100);
// use it like an array -- in this case set them all to 22/7
for (i = 0; i < 99; i++) {
fracts[i].numerator = 22;
fracts[i].denominator = 7;
}
// Deallocate the whole array
free(fracts);
}
Allocating Array on Heap
54. /*
Given a C string, return a heap allocated copy of the string.
Allocate a block in the heap of the appropriate size,
copies the string into the block, and returns a pointer to the block.
The caller takes over ownership of the block and is responsible
for freeing it.
*/
char* StringCopy(const char* string) {
char* newString;
int len;
len = strlen(string) + 1; // +1 to account for the '0'
newString = malloc(sizeof(char) * len);
// elem-size * number-of-elements
dynamic size
assert(newString != NULL);
// simplistic error check (a good habit)
strcpy(newString, string);
// copy the passed in string to the block
return (newString); // return a ptr to the block
} long lifetime
Allocating String on Heap
55. typedef long Align; /* for alignment to long boundary */
union header { /* block header */
struct {
union header *ptr; /* next block if on free list */
unsigned size; /* size of this block */
} s;
Align x; /* force alignment of blocks */
};
typedef union header Header; Free List
static Header base; /* empty list to get started */
static Header *freep = NULL; /* start of free list */
56. Memory is allocated, but not deallocated
• heap gradually fills up
• program runs out of heap space
• crash
Ownership
• stringCopy() does not own allocated memory
• caller is responsible for deallocation
Memory management
• requires careful administration of memory allocated
Memory Leaks
57. lifetime of a variable: interval between creation
(allocation) and destruction (deallocation)
global variable: declared for use throughout the
program; lifetime is program’s run-time
local variable: declared within a block, for use only
within that block; lifetime is activation of block
heap variable: can be created and destroyed at any
time during the program’s run-time; arbitrary lifetime
bound by program run-time
persistent variable: lifetime transcends activation
of a program
58. Study Question: How is memory
management arranged in Java,
Scala, JavaScript, ...?
59. Reading & Programming in Week 3
Reading
Sebesta C6: Data Types
Programming in Scala Ch6: Functional Objects
Parlante: Memory and pointers in C
WebLab:
C, JavaScript, Scala tutorials
Grammars and regular expressions
Week 4: Data Types