指针和引用
8.1 什么是指针
指针是存储内存地址的变量,与所有变量一样, 指针也占用内存空间,在下图中,其地址为0x101,指针的值被解读为内存地址。
8.1.1 指针的初始化
指针需要初始化,否则会指向为随机地址。指针初始化代码如下:
int *pointToInt = NULL;
8.1.2 使用引用运算符(&)获取变量的地址
&变量名 是存储该变量的内存的地址。例如:
int age = 30;
cout << "Integer age is located at: 0x" << &age << endl;
结果如下:
Integer age is located at: 0x0000007F08CFFAB4
8.1.3 使用指针存储地址
代码如下:
int age = 30;
int* pointToInt = &age;
cout << hex << pointToInt << endl; //hex是让输出值16进制显示
给上面的指针重新赋值,让其指向另一个变量。
int age = 30;
int* pointToInt = &age;
cout << hex << pointToInt << endl;
int dog = 9;
pointToInt = &dog;
cout << hex << pointToInt << endl;
结果如下:
0000002AA7EFF9E4
0000002AA7EFFA24
8.1.4 使用解除引用运算符(*)访问指针指向的数据
代码如下:
int age = 30;
int* pointToInt = &age;
cout << hex << pointToInt << endl;
cout << dec << *pointToInt << endl; //dec是十进制
int dog = 9;
pointToInt = &dog;
cout << hex << pointToInt << endl;
cout << dec << *pointToInt << endl;
结果如下:
00000003525AF954
30
00000003525AF994
9
使用解引用运算符操纵指针:
int age = 30;
int* pointToInt = &age;
cout << hex << pointToInt << endl;
cout << dec << *pointToInt << endl;
cin >> *pointToInt;
cout << hex << pointToInt << endl;
cout << dec << *pointToInt << endl;
cout << age << endl;
结果如下:
00000068AAF1F5E4
30
10
00000068AAF1F5E4
10
10
在修改了*pointToInt之后,指针pointToInt值不变,*pointToInt变了,说明指向的值变了。
8.1.5 sizeof()用于指针
cout << hex << pointToInt << endl;
cout << dec << *pointToInt << endl;
cout << age << endl;
cout << "sizeof fundamental types -" << endl;
cout << "sizeof (char) = " << sizeof(char) << endl;
cout << "sizeof (int) = " << sizeof(int) << endl;
cout << "sizeof (double) ="<< sizeof (double) << endl;
cout << "sizeof pointers to fundamental types -" << endl;
cout << "sizeof (char*) = "<< sizeof(char*) << endl;
cout << "sizeof (int*) = " << sizeof(int*) << endl;
cout << "sizeof (double*) = " << sizeof(double*) << endl;
结果如下:
sizeof fundamental types -
sizeof (char) = 1
sizeof (int) = 4
sizeof (double) =8
sizeof pointers to fundamental types -
sizeof (char*) = 8
sizeof (int*) = 8
sizeof (double*) = 8
8.2 动态内存分配
8.2.1 使用new和delete动态地分配和释放内存
使用new可以分配新的内存空间。如果成功,new将返回指向一个指针;使用new时,需要指定要为哪种数据类型分配内存:
- 分配单个内存:
语法: Type* Pointer = new Type;
delete Pointer; - 分配多个内存:
语法: Type* Pointer = new Type[num];
delete[] Pointer;
代码如下:
int* pointToAnAge = new int;
cin >> *pointToAnAge;
cout << "Age " << *pointToAnAge << "is stored at 0x" << hex << pointToAnAge << endl;
delete pointToAnAge;
结果如下:
10
Age 10 is stored at 0x0000027120517180
分配多个内存代码 如下:
int num = 0;
cin >> num;
int* pointToAnAge = new int[num];
cout << "Age is stored at 0x" << hex << pointToAnAge << endl;
delete[] pointToAnAge;
结果如下:
10
Age is stored at 0x000001B46F87F0C0
8.2.2 将递增和递减运算符(++和–)用于指针运算
对指针pointToInt执行递增运算(pointToInt++),将导致它增加4个字节,即sizeof(int)。将++用于该指针相当于编译器,希望它指向下一个int。同理,使用–则导致指针减少4个字节。
int num = 0;
cin >> num;
int* pointToAnAge = new int[num];
for (int cnt = 0; cnt < num; ++cnt) {
cin >> *(pointToAnAge + cnt);
}
for (int cnt = 0; cnt < num; ++cnt) {
cout << *(pointToAnAge++) << " ";
}
pointToAnAge -= num;
delete[] pointToAnAge;
结果如下:
8.2.3 将关键字const用于指针
const指针有如下三种:
- 指针包含的地址是常量,不能修改,但可修改指针指向的数据:
int daysInMonth = 30;
int* const pDaysInMonth = &daysInMonth;
*pDaysInMonth = 31; // OK! Data pointed to can be changed
int daysInLunarMonth = 28;
pDaysInMonth = &daysInLunarMonth; // Not OK! Cannot change address!
- 指针指向的数据为常量,不能修改,但可以修改指针包含的地址,即指针可以指向其他地方:
int hoursInDay = 24;
const int* pointsToInt = &hoursInDay;
int monthsInYear = 12;
pointsToInt = &monthsInYear; // OK!
*pointsToInt = 13; // Not OK! Cannot change data being pointed to
int* newPointer = pointsToInt; // Not OK! Cannot assign const to non-const
- 指针包含的地址以及它指向的值都是常量,不能修改(这种组合最严格):
int hoursInDay = 24;
const int* const pHoursInDay = &hoursInDay;
*pHoursInDay = 25; // Not OK! Cannot change data being pointed to
int daysInMonth = 30;
pHoursInDay = &daysInMonth; // Not OK! Cannot change address
8.2.4 将指针传递给函数
void CalcArea(const double* const ptrPi, // const pointer to const data
const double* const ptrRadius, //no changes allowed
double *const ptrArea) // can change data pointed to
{
if (ptrPi && ptrRadius && ptrArea)//检查指针合法性
{
*ptrArea = (*ptrPi) * (*ptrRadius) * (*ptrArea);
}
}
8.2.5 数组和指针的类似之处
当定义一个指向数组中第一个元素的指针时,存储在指针中的地址与数组第一个元素在内存中的地址相同。
int myNumbers[5];
int* pointToNums = myNumbers;
cout << "pointToNums = 0x" << hex << pointToNums << endl;
cout << "&myNumbers[0] = 0x" << hex << &myNumbers[0] << endl;
cout << "myNumbers[1] = " << *(pointToNums + 1) << endl;
cout << "myNumbers[1] = " << myNumbers[1] << endl;
结果如下:
pointToNums = 0x000000226370FB98
&myNumbers[0] = 0x000000226370FB98
myNumbers[1] = cccccccc
myNumbers[1] = cccccccc
8.2.6 使用*访问数组中的元素以及将数组运算符[]用于指针
const int ARRAY_LEN = 5;
// Static array of 5 integers, initialized
int myNumbers[ARRAY_LEN] = { 24, -1, 365, -999, 2011 };
// Pointer initialized to first element in array
int* pointToNums = myNumbers;
cout << "Display array using pointer syntax, operator*" << endl;
for (int index = 0; index < ARRAY_LEN; ++index)
cout << "Element " << index << " = " << *(myNumbers + index) << endl;
cout << "Display array using ptr with array syntax, operator[]" << endl;
for (int index = 0; index < ARRAY_LEN; ++index)
cout << "Element " << index << " = " << pointToNums[index] << endl;
结果如下:
Display array using pointer syntax, operator*
Element 0 = 24
Element 1 = -1
Element 2 = 365
Element 3 = -999
Element 4 = 2011
Display array using ptr with array syntax, operator[]
Element 0 = 24
Element 1 = -1
Element 2 = 365
Element 3 = -999
Element 4 = 2011
8.3 使用指针时常犯的编程错误
8.3.1 内存泄漏
int* pointToNums = new int[5]; // initial allocation
// use pointToNums
...
// forget to release using delete[] pointToNums;
...
// make another allocation and overwrite
pointToNums = new int[10]; // leaks the previously allocated memory