天天看点

C++ Pointers and Dynamic Memory ManagementLast!!!

In order to remember the usages of the pointer, I summarize it.

1st. What is a pointer?

Pointer variables, simply called pointers, are declared to hold memory addresses as their values.

2nd. To declare a pointer

For example:

The following statements declare pointers named pCount, pStatus, pLetter and pString which can point to an int variable, a short variable, a char variable, and a string, respectively.
int* pCount; 
short* pStatus; 
char* pLetter; 
string* pString;
           

3rd. To assign a pointer

Assign the address of a variable to the pointer

For instance:

int count;
int* pcount = &count;
           

Actually, &count is the address of count.

& symbol is called the address operator when placed in front of a variable. It is a unary operator that returns the variable’s address.

Attention:

Like a local variable, a local pointer is assigned an arbitrary value if you don’t initialize it. To prevent errors, you should always initialize pointers.

eg:

int* pCount1 = 0; 
int* pCount2 = NULL; // A number of C++ libraries 
                     //including <iostream> define 
                     //NULL as a constant with value 0
           

4th. To reference a value through a pointer

C++ Pointers and Dynamic Memory ManagementLast!!!
The asterisk (*) used in the preceding statement is known as the indirection operator (间接引用运算符) or dereference operator (解引用运算符). When a pointer is dereferenced, the value at the address stored in the pointer is retrieved.

For example:

int count = 5; 
int* pCount = &count; 
cout << "The value of count is " << count << endl; 
cout << "The address of count is " << &count << endl; 
cout << "The address of count is " << pCount << endl; 
cout << "The value of count is " << *pCount << endl;
           

The results are:

The value of count is 5

The address of count is 0x6dfef8

The address of count is 0x6dfef8

The value of count is 5

5th. The usage of typedef

For instance:

typedef int integer;
integer value = 40;
typedef int* intPointer;
intPointer p; //which is the same as int* p;
           

One advantage of using a pointer type name is to avoid the errors involving missing asterisks.

int* p1, p2; //p1 is pointer, p2 is int
typedef int* intPointer; 
intPointer p1, p2;//p1 and p2 are pointers
           

6th. Constant pointer

A constant pointer points to a constant memory location, but the actual value in the memory location can be changed.

To declare a constant pointer:

double radius = 5;
double* const p = &radius; 
           
p is a constant pointer. It must be declared and initialized in the same statement. You cannot assign a new address to p later.

Though p is a constant, the data pointed to by p is not constant. You can change it.

double radius = 5; 
double* const p = &radius; //p is a constant pointer. 
(*p) = 7; //radius = 7, radius is 7 now 
double r2 = 10; 
p = &r2; //error: assignment of read-only variable 'p'
           

Also, we can declare the dereferenced data to be a constant:

C++ Pointers and Dynamic Memory ManagementLast!!!
In this case, the pointer is a constant, and the data pointed to by the pointer is also a constant.

Several Examples:

double radius = 5;
double* const p = &radius;
double length = 5;
*p = 6; // OK 
p = &length; // Wrong because p is constant pointer 
const double* p1 = &radius; 
*p1 = 6; // Wrong because p1 points to a constant data 
p1 = &length; // OK 
const double* const p2 = &radius; 
*p2 = 6; // Wrong because p2 points to a constant data 
p2 = &length; // Wrong because p2 is a constant pointer
           

7th. Arrays and pointers

A C++ array name is actually a constant pointer to the first element in the array.
  • Name of an array represents the starting address:

    myList = &myList[0];

  • A pointer for an array can be used just like an array. You can even use pointer with index.
int list[6] = {11, 12, 13, 14, 15, 16};
int* p = list;
for (int i = 0; i < 6; i++) 
	cout << "address: " << (list + i) << 
	" value: " << *(list + i) << " " << 
	" value: " << list[i] << " " << 
	" value: " << *(p + i) << " " << 
	" value: " << p[i] << endl;
           
  • The difference between pointer and array name is that Array name is a constant address:
int array[10]; 
int* ptr = array; 
for (int i = 0;i < 5; i ++) { 
	cout<< *(ptr++) << " ";   // OK 
	cout<< *(array++) << " "; // Wrong 
}
           

8th. Pointers in functions

If we define a function:

Now,let’s consider invoking function f(q1, q2) with two pointers q1 and q2:

1. The pointer q1 is passed to p1 by value. So *p1 and *q1 point to the same contents. If function f changes *p1 (e.g., *p1 = 20), *q1 is changed too. However, if function f changes p1 (e.g., p1 = somePointerVariable), q1 is not changed.

2. The pointer q2 is passed to p2 by reference. So q2 and p2 are now aliases. They are essentially the same. If function f changes *p2 (e.g., *p2 = 20), *q2 is changed too. If function f changes p2 (e.g., p2 = somePointerVariable), q2 is changed too.

The address stored in a pointer is returned. Suppose you want to write a function that passes an array argument, reverses it, and returns the array.

eg:

int* reverse(int* list, int size) 
{ 
	for (int i = 0, j = size - 1; i < j; i++, j--) { 
		// Swap list[i] with list[j] 
		int temp = list[j]; 
		list[j] = list[i]; 
		list[i] = temp; 
	}  
return list; 
}
void main(){ 
	int list[] = {1, 2, 3, 4, 5, 6}; 
	int* p = reverse(list, 6); 
	for (int i = 0; i < size; i++) 
		cout << list[i] << " "; 
	return 0; 
	}
           
  • Remember, don’t return a local pointer! It becomes invalid after the return!

9th. Several useful array functions

The min_element, max_element, sort, random_shuffle, and find functions can be used for arrays (#include <algorithm>).

Especially, All these functions use pointers in the arguments and in the return value.

eg:

int list[] = {4, 2, 3, 6, 5, 1}; 
int* min = min_element(list, list + 6); 
int* max = max_element(list, list + 6); 
cout<< "The min value is " <<*min<< " at index " <<(min - list)<<endl; 
random_shuffle(list, list + 6); 
sort(list, list + 6);

int key = 4; 
int* p = find(list, list + 6, key); 
if (p != list + 6) 
	cout << *p << " is found at position " << (p - list) << endl; 
else 
	cout << *p << " is not found" << endl;
           

10th. Dynamic persistent memory allocation

The new operator can be used to create persistent memory at runtime for primitive type values, arrays, and objects.

For example:

int* p1 = new int(4);//int number
//Dynamic array:
int* p2 = new int[10];//int array
int* p3 = new int[size];//int array
           

To explicitly free the memory created by the new operator, use the delete operator.

For instance:

delete p1; // delete operator for a pointer 
delete [] p2; // delete operator for an array
           

Note: As a good programming practice, every call to new should be matched by a call to delete!

However, it will cause memory leak with the following code:

int* p = new int;
*p = 45;
p = new int; 
           
C++ Pointers and Dynamic Memory ManagementLast!!!

Last!!!

对于曾经Pascal选手来讲,指针真的不会用。。。正好临近考试,总结出来指针的用法(虽然是英文),对于那么聪明的你们来讲,一定可以有办法把它翻译成中文的吧!

Especially:

C++ Pointers and Dynamic Memory ManagementLast!!!

At last, thanks to my teacher Assoc Prof. Qian SUN’s slides!