Previous Lecture lect04 Next Lecture

Relevant topics in the textbook:

Data Structures and Other Objects Using C++ Chapter 4.1

Pointer Arithmetic

// Recall
// void printArray(int* values, int size) { // can use a pointer
void printArray(int values[], int size) {
	// Note: size is passed in since we won’t know how to get the size with
	// just the array variable.

	cout << values << endl; // prints memory location of start of values[]

	for (int i = 0; i < size; i++) {
		cout << "values[" << i << "] = " << values[i] << endl;
		cout << "&values[" << i << "] = " << &values[i] << endl;
		// Note: The address values are 4 bytes away since int is 4 bytes
	}
}

int main() {
	int values[3] = { 5, 10, 15 };
	printArray(values, 3);
	return 0;
}

Example

int main() {
	int arr[5] = {0,1,2,3,4};
	int* x = arr;

	cout << arr << endl;
	cout << x << endl;

	cout << x + 1 << endl; // address is incremented by 1*sizeof(int)
	cout << x + 2 << endl; // address is incremented by 2*sizeof(int)
	cout << x + 3 << endl; // address is incremented by 3*sizeof(int)

	cout << *(x + 2) << endl;	// equivalent to x[2] or arr[2]
	cout << &(*(x + 2)) << endl;  // equivalent to x + 2
	return 0;
}

Illustration

elementAddress = startOfArrayAddress + (i * (size of type pointer is pointing to))

Example - trace the code

int arr[] = {10,15,20};
int* x;
x = arr;
cout << x + 1 << endl; // Address of arr[1]
cout << *x + 1 << endl; // 11

Example - using [ ] and pointer arithmetic

void initializeArray(int* values, int size, int initialValue) {
	for (int i = 0; i < size; i++) {
		values[i] = initialValue;
		cout << values[i] << “ “;
	}
}
	for (int i = 0; i < size; i++) {
		*(values + i) = initialValue;
		cout << *(values + i) << " ";
	}

Segmentation Faults

for (int i = 0; i < 1000000; i++) {
	*(values + i) = initialValue;
}

Another Example - passing pointers by value / reference

void incrementPointer(int* p) {
	p++;
}

int main() {
	int arr[] = {10,20,30};
	int* x = arr;

	incrementPointer(x);

	cout << *x << endl; // 10
	return 0;
}
void incrementPointer(int*& p) {
	p++;
}
void incrementPointer(int** p) {
	//p++;		
	*p = *p + 1;	// need to modify the original pointer’s address
}

int main() {
	int arr[] = {1,2,3};
	int* x = arr;

	incrementPointer(&x); 	// since a pointer to a pointer expects the address of
				// a pointer to an int. 
	cout << *x << endl;
	return 0;
}

Dynamic Memory Management

Heap

“new” operator

Example

int* p = new int(10);	// allocate an int on the heap and point p to it
*p = 2;			// sets the int value to 2 (without address change)
int& q = *p;		// q refers to the value that p points to
q = 4;			// change int value to 4

cout << *p << endl;	// prints 4

int* r = &q;		// make r point to the address that q refers to
*r = 6;			// change int value that r points to to 6

cout << *p << endl;	// prints 6
cout << q << endl;	// prints 6
cout << *r << endl;	// prints 6

“delete” operator

Example of memory leaks

void g(int x) {
	int* p = new int(x);	// memory leak!
	delete p;		// remove this and see application size grow!
	return;
}

int main() {
for (int i = 0; i < 100000000; i++)
		g(i);
}

Dangling Pointers

Dangling Pointers Example

int g(int x) {
	double* p = new double(x);
	delete p;	// delete value from the heap
	return *p; 	// p is a dangling pointer since heap contents were removed!
			// Results in undefined behavior. Shouldn’t do this!
}

Dynamically allocating arrays

int* arr = new int[10];	// create an array of 10 integers on the heap
delete [] arr;		// removes the array from the heap. Note the [] syntax for deleting arrays from the heap.
int x;
cout << "Enter a positive number: ";
cin >> x;
// int intArray[x]; // ERROR IN VisualStudio, NOT g++ / clang++
int* intArray = new int[x]; // LEGAL IN BOTH
for (int i = 0; i < x; i++) {
	intArray[i] = i;
	cout << intArray[i] << endl;
}

// Note: to delete an array on the heap, use delete [] intArray;
delete [] intArray;