目录
一、基本概念
指针是一个变量,其存储的是值的地址,而不是值本身。通过对变量应用地址运算符(&)就可以获得它的地址,示例程序如下:
//address.cpp -- 使用地址运算符&来获取变量值的存储地址,例 &variablename #include <iostream> using namespace std; int main() { int donuts = 6; double cups = 4.5; cout << "donuts value = " << donuts; cout << " and donuts address = " << &donuts << endl; cout << "cups value = " << cups; cout << " and cups address = " << &cups << endl; return 0; }
指针变量中存储的是地址信息,对指针变量应用间接值(又称解除引用)运算符(*),可以得到该地址处存储的值,示例程序如下(该程序还演示了如何声明指针):
//pointer.cpp -- 指针变量 #include <iostream> using namespace std; int main() { int updates = 6; //声明一个整型变量 int * p_updates; //声明一个指针变量,*运算符被称为间接值或解除引用运算符 p_updates = &updates; //获取地址赋给指针 //用两种方式表达值 cout << "Value: updates = " << updates; cout << ", *p_updates = " << *p_updates << endl; //用两种方式表达地址 cout << "Address: &updates = " << &updates; cout << ", p_updates = " << p_updates << endl; //利用指针改变变量的值 *p_updates = *p_updates + 1; cout << "New updates = " << updates << endl; return 0; }
二、声明和初始化指针
- 指针声明必须指定指针指向的数据的类型。
- 对每个指针变量名,都需要使用一个*。
- 可以在声明语句中初始化指针,在这种情况下,被初始化的是指针,而不是它指向的值。
示例程序如下:
int higgens = 5;
int * pt = &higgens; // 声明指针变量并初始化
注意:一定要在对指针应用解除引用运算符(*)之前,将指针初始化为一个确定的、适当的地址。
三、使用 new 来分配内存
将指针初始化为变量的地址,变量是在编译时从栈(stack)中分配的有名称的内存,而指针只是为可以通过名称直接访问的内存提供了一个别名。指针真正的用武之地在于,使用 new 运算符在运行阶段从被称为堆(heap)或自由存储区(free store)的内存区域中分配未命名的内存以存储值,在这种情况下,只能通过指针来访问内存。此时,指针指向的内存没有名称,我们可以说指针指向一个数据对象,它指的是为数据项分配的内存块。
为一个数据对象(可以是结构,也可以是基本类型)获得并指定分配内存的通用格式如下:
typeName * pointer_name = new typeName;
需要在赋值运算符前后指定数据类型:用来指定需要什么样的内存和用来声明合适的指针。示例程序如下://use_new.cpp -- 使用new运算符,在程序运行阶段分配未命名的内存以存储值,格式:typename * pointer_name = new typename; #include <iostream> using namespace std; int main() { int nights = 1001; int * pt = new int; //为存储int分配内存 *pt = 1001; //在分配的内存中存储值1001 cout << "nights value = "; cout << nights << ": location " << &nights << endl; cout << "int "; cout << "value = " << *pt << ": location " << pt << endl; double * pd = new double; //为存储double分配内存 *pd = 10000001.0; //在分配的内存中存储值10000001.0 cout << "double "; cout << "value = " << *pd << ": location " << pd << endl; cout << "location of pointer pd: " << &pd << endl; cout << "size of pt = " << sizeof(pt); cout << ": size of *pt = " << sizeof(*pt) << endl; cout << "size of pd = " << sizeof(pd); cout << ": size of *pd = " << sizeof(*pd) << endl; return 0; }
四、使用 delete 来释放内存
当需要内存时,可以使用 new 来请求,如果通过 new 请求的内存在使用完后没有及时释放,将发生内存泄漏(memory leak),也就是说,被分配的内存再也无法使用了,如果内存泄漏严重,则程序将由于不断寻找更多内存而终止。所以,使用 new 运算符分配内存后,需要使用 delete 运算符释放内存,防止内存泄漏,用法如下:
int * pt = new int; // 分配内存
..... // 使用内存
delete pt; // 释放内存
这将释放指针指向的内存,但不会删除指针本身。
不要尝试释放已经释放的内存块,只能用 delete 来释放使用 new 分配的内存,然而,对空指针使用 delete 是安全的。
五、使用 new 来创建动态数组
在编译时给数组分配内存被称为静态联编(static binding),意味着数组是在编译时加入到程序中的。但使用 new 时,如果在运行阶段需要数组,则创建它;如果不需要,则不创建。还可以在程序运行时选择数组的长度。这被称为动态联编(dynamic binding),意味着数组是在程序运行时创建的,这种数组叫作动态数组(dynamic array)。使用静态联编时,必须在编写程序时指定数组的长度;使用动态联编时,程序将在运行时确定数组的长度。
1.创建动态数组
在C++中要创建动态数组,只要将数组的元素类型和元素数目告诉 new 即可,必须在类型名后加上方括号,其中包含元素数目。创建动态数组的通用格式如下:
type_name * pointer_name = new type_name [ num_elements ] ;
使用 new 运算符可以确保内存块足以存储 num_elements 个类型为 type_name 的元素,而 pointer_name 将指向第一个元素。
当程序使用完 new 分配的内存块时,应使用 delete 释放它们。然而,对于使用 new 创建的数组,应使用另外一种格式的 delete 来释放:
delete [ ] pointer_name ;2.使用动态数组
可以以使用数组名的方式来使用 pointer_name,示例程序如下:
//arraynew.cpp -- 使用new运算符创建动态数组 #include <iostream> using namespace std; int main() { double * p3 = new double[3]; //分配内存,存储三个double类型的元素 p3[0] = 0.2; //将指针看作数组名,用数组表示法访问数组元素 p3[1] = 0.5; p3[2] = 0.8; cout << "p3[1] is " << p3[1] << ".\n"; p3 = p3 + 1; //将指针+1,这里显示指针和数组名的区别,数组名的值不能被修改,但指针是变量,可以修改值 cout << "Now p3[0] is " << p3[0] << " and "; cout << "p3[1] is " << p3[1] << ".\n"; p3 = p3 - 1; //指针指向原来的值,使程序可以给delete [] 提供正确的地址 delete[] p3; //使用new [] 为数组分配内存,则应使用delete [] 来释放内存 return 0; }