指针是一个变量,其存储的是值的地址,而不是值本身。
对变量应用地址运算符(&),就可以获得它的位置。
使用常规变量时,值是指定的量,而地址为派生量。下面来看看指针策略,它是C++内存管理编程理念的核心。
指针与C++基本原理
面向对象编程与传统的过程性编程的区别在于,OPP强调的是在运行阶段(而不是编译阶段)进行决策。运行阶段指的是程序正在运行时,编译阶段指的是编译器将程序组合起来时。
运行阶段决策提供了灵活性,可以根据当时的情况进行调整。在运行阶段做决策并非OPP独有的,但使用C++编写这样的代码比使用C语言简单。
处理存储数据的新策略刚好相反,将地址视为指定的量,而将值视为派生量。一种特殊类型的变量——指针用于存储值得地址。因此,指针名表示的是地址。*运算符被称为间接值或解除引用运算符,将其应用于指针,可以得到该地址处存储的值(这和乘法使用的符号相同;C++根据上下文来确定所指的是乘法还是解除引用)。例如,假设manly是一个指针,则manly表示的是一个地址,而*manly表示存储在该地址处的值。*manly与常规int变量等效。
声明和初始化指针
指针声明必须指定指针指向的数据的类型。
int*P_updates
这表示,*p_updates的类型为int。由于*运算符被用于指针,因此p_updates变量本身必须是指针。我们说p_updates指向int类型,我们还说p_updates的类型是指向int的指针,或int*。可以这样说,p_updates是指针(地址),而*p_updates是int,而不是指针。
int *ptr;//传统上,C程序员使用这种格式。这强调*ptr是一个int类型的值。 int* ptr;//很多C++程序员使用这种格式。这强调的是:int*是一种类型——指向int的指针。 /*下面的声明创建一个指针(p1)和一个int变量(p2)*/ int* p1,p2; /*对每个指针变量名,都需要使用一个*在C++中,int*是一种复合类型,是指向int的指针。*/
可以在声明语句中初始化指针。在这种情况下,被初始化的是指针,而不是它指向的值。也就是说,下面的语句将pt(而不是*pt)的值设置为&higgens:
int higgens=5; int* pt=&higgens;
指针的危险
极其重要的一点是:在C++创建指针时,计算机将反派用来存储地址的内存,但不会分配用来存储指针所指向的数据的内存。为数据提供空间是一个独立的步骤,忽略这一步无疑是自找麻烦,如下所示:
long* fellow; *fellow=223323;
fellow确实是一个指针,但它指向哪里呢?上述代码没有将地址赋给fellow。由于fellow没有被初始化,它可能有任何值。不管值是什么,程序都将它解释为存储223323的地址。如果fellow的值碰巧是1200,计算机将把数据放在地址,计算机将把数据放在地址1200上,即使这恰巧是程序代码的地址。fellow指向的地方很可能并不是所要存储223323的地方。这种错误可能会导致一些最隐匿、最难以跟踪的bug。
一定要在对指针应用解除引用运算符(*)之前,将指针初始化为一个确定的、适当的地址。这是关于使用指针的金科玉律。
指针和数字
不能简单地将整数赋给指针:
int* pt; pt=0xB8000000;
在这里,左边是指向int的指针,因此可以把它赋给地址,但右边是一个整数。您可能知道,0xB8000000是老式计算机系统中视频内存的组合段偏移地址,但这条语句并没有告诉程序,这个数字就是一个地址。在C99标准发布之前,C语言允许这样赋值。但C++在类型一致方面的要求更严格,编译器将显示一条错误信息,通告类型不匹配。要将数字值作为地址来使用,应通过强制类型转换将数字转换为适当的地址类型:
int* pt; pt=(int*)0xB8000000;
使用new来分配内存
/*use_new.cpp*/ #include<iostream> int main() { using namespace std; int nights = 1001; /*使用new为int类型的数据对象分配内存。这是在程序运行时进行的。 有了指针,就可以像使用变量那样使用*pt。将值赋给*pt,从而将这些值赋给新的数据对象。 new分配的内存块通常与常规变量声明分配的内存块不同。变量nights和pd的值都储存在被称为栈(stack)的内存区域中,而new从被称为堆(heap)或自由存储区(free store)的内存区域分配内存*/ int* pt = new int; *pt = 1001; cout << "nights 的值="; cout << nights << ":地址" << &nights << endl; cout << "整型"; cout << "值=" << *pt << ":地址=" << pt << endl; double*pd = new double; *pd = 10000001.1; cout << "浮点型"; cout << "值=" << *pd << ":地址=" << pd << endl; cout << "指针pd的地址:" << &pd << endl; cout << "pt的大小=" << sizeof(pt); cout << "*pt的大小=" << sizeof(*pt) << endl; cout << "pd的大小=" << sizeof pd; cout << ":*pd的大小=" << sizeof(*pd) << endl; cin.get(); cin.get(); return 0; }
使用new来创建动态数组
/*arranew.cpp*/ #include<iostream> int main() { using namespace std; /*为数组分配内存的通用格式:type_name* pointer_name=new name[num_elements];*/ double* p3 = new double[3]; p3[0] = 0.2; p3[1] = 0.5; p3[2] = 0.8; cout << "p3[1] is" << p3[1] << ".\n"; /*不能修改数组名的值。但指针是变量,因此可以修改它的值。 p3加1导致它指向第2个元素而不是第1个*/ p3 = p3 + 1; cout << "Now p3[0] is" << p3[0] << "and"; cout << "p3[1] is" << p3[1] << ".\n"; /*p3减1后,指针将指向原来的值,这样程序便可以给delete[]提供正确的地址。*/ p3 = p3 - 1; /*方括号告诉程序,应释放整个数组,而不仅仅是指针指向的元素*/ delete[]p3; cin.get(); cin.get(); return 0; }
输出
p3[1] is 0.5. Now p3[0] is 0.5 and p3[1] is 0.8.