# Pointers and Dynamic Memory Allocation

Tom Kelliher, CS23

Mar. 10, 1997

# Pointer Variables

Recall:

• Lvalue
• Rvalue

The rvalue of a pointer variable of type T is the lvalue of a variable of type T.

Consider the trivial example:

```int i;
int j;
int *pi = &i;   // sets pi's rvalue to i's lvalue
*pi = 1;        // sets i to 1
pi = &j;        // sets pi's rvalue to i's lvalue
*pi = 2;        // sets j to 2
```

Assume:

1. i is allocated 4 bytes at 0x1000 (lvalue)
2. j is allocated 4 bytes at 0x1004 (lvalue)
3. pi is allocated 4 bytes at 0x1008 (lvalue)
What are the rvalues during execution?

## Pointer Assignment

Valid assignments:

1. NULL
2. Another pointer of the same type
3. Lvalue of appropriately-typed variable
4. Appropriate pointer expressions

Which of the assignments are valid/invalid?

```int i;
int j;
char c;
double x;
int* ip;
char* cp;
float* fp;

ip = &i;
cp = NULL;
ip = cp;
ip = j;
fp = &x;
cp = &i;
cp = (char*)&i;
cp = &c;
cp += 12;
cp *= 2;
```

The most common mistake with pointer parameters:

```void f(int *ip)
{
*ip = 0;
}

void g(void)
{
int i;

f(i);
}
```
What error message from compiler?

Most common ``fix?''

# Memory Segments for Data

1. Stack segment --- local data
2. Data segment --- static data, ``large'' arrays
3. Heap segment --- dynamic data: ``nameless'' variables

Variable attributes:

2. Scope
3. Visibility

```int* makeInt(void)
{
static i = 0;
int* pi;
pi = new int;
assert (pi != NULL);
return pi;
}   // Lifetime/Scope of i, pi, "new int"?
```

# Allocating Memory from the Free Store

AKA heap segment

Two operators:

• new <type>
• delete <type>

<type> can be any type --- primitive, derived, or even a class

Examples:

```int* pi;
pi = new int;       // allocate a single int
*pi = 0;            // modify the new int
delete pi;          // de-allocate
*pi = 0;            // design error to reference de-allocated memory
delete pi;          // *serious* design error
pi = new int[10];   // allocate int array
pi[1] = 3;
delete [] pi;       // [] necessary to ensure proper de-allocation
// of array
pi = NULL;          // good programming practice
delete pi;          // no damage

// allocate a struct
employeeRecord* employee = new employeeRecord;
employee = NULL;   // memory leak
```

Relevant points:

1. new <type> returns <type>*
2. Don't reference something deleted
3. Don't delete more than once
4. Good design practice: NULL the operand of a delete
5. (Because) OK to multiply delete NULL
6. Don't permit memory leaks

# Example: A Simple Array Class

client code:

```#include <iostream.h>
#include "array.h"

int main()
{
IntArrayClass array(10);   // array has 10 elements, all zero'ed
int i;

for (i = 0; i < array.size(); i++)   // fill the array
array.set(i, i);

for (i = 0; i < array.size(); i++)   // print

array.resize(20);   // 10 new elements

for (i = 0; i < array.size(); i++)   // print the enlarged array

array.resize(5);  // shrink the array

for (i = 0; i < array.size(); i++)   // print

return 0;
}
```

array.h:

```class IntArrayClass
{
public:
IntArrayClass(int size);
~IntArrayClass(void);
int size(void);
void set(int index, int value);
int resize(int newSize);

private:
int elems;
int *ia;
};
```

array.cc:

```#include <assert.h>
#include <stdlib.h>
#include "array.h"

// construct an int array with size elements, zero them

IntArrayClass::IntArrayClass(int size)
{
int i;

assert (size >= 0);

elems = size;
ia = new int[elems];
assert (ia != NULL);

for (i = 0; i < elems; i++)
ia[i] = 0;
}

// de-allocate an array

IntArrayClass::~IntArrayClass(void)
{
delete [] ia;
ia = NULL;
}

// return number of elements in array

int IntArrayClass::size(void)
{
return elems;
}

// return value of one element of the array

{
assert (0 <= index && index < elems);
return ia[index];
}

// set value of one element of the array

void IntArrayClass::set(int index, int value)
{
assert (0 <= index && index < elems);
ia[index] = value;
}

// make the array larger or smaller
// making it smaller truncates elements from the end
// making it larger adds new 0 elements to the end

int IntArrayClass::resize(int newSize)
{
int *ta;
int i;
int limit;

assert (newSize >= 0);

// allocate space for the new array, which may be larger *or* smaller
// than the old array

ta = new int[newSize];   // Typo fixed.
assert (ta != NULL);

// determine point at which to stop copying elements from old array
// to new array

limit = (elems < newSize) ? elems : newSize;

for (i = 0; i < limit; i++)   // copy elements
ta[i] = ia[i];

// zero the enlarged part of the array, if necessary

for ( ; i < newSize; i++)
ta[i] = 0;

delete [] ia;   // delete old array

ia = ta;        // "remember" new array
elems = newSize;
}
```

Thomas P. Kelliher
Sat Mar 8 11:10:15 EST 1997
Tom Kelliher