一、自由存储空间
计算机程序在存储数据时必须跟踪的3种基本属性:
1、信息存储的位置在哪里
2、存储的值是多少
3、存储的信息是什么类型
开发人员可以通过声明语句定义一个简单变量,指出值的类型和名称,分配内存并对该内存单元进行跟踪。除此之外定义了一种数据类型称之为指针,该类型变量存储的是值的地址,而不是值本身。相似的可以了解常规变量的地址获取,使用取地址运算符&就可以获取对应变量的地址 。
#include <iostream>
int main()
{
using namespace std;
int donuts = 6;
double cups = 4.5;
cout << "donuts value = " << donuts ;
cout << "donuts address = " << &donuts << endl ;
cout << "cups value = " << cups;
cout << "cups address = " << &cups << endl ;
}
面向对象编程(OOP)与传统的过程性编程的区别在于,OOP强调运行阶段(而不是编译阶段)进行决策,即程序正在运行时根据当时的情况进行调整而效果灵活。而编译阶段指的是编译器将程序组合起来时,已经完成决策的设定。
比如为数组分配内存的情况,传统的方法是声明一个数组,指定数组的最大长度,在程序编译时就设定好了,这可能会导致内存的浪费,但这就是编译决策。OOP将这样的决策推迟到运行阶段执行,使得程序更加灵活,根据实际需要申请内存,C++采用的方法是使用关键字请求正确数量的内存以及使用指针来跟踪新分配的内存的位置。
二、特殊类型变量-指针
作为对比,使用常规变量时,值是指定的量,而地址是派生量。使用指针变量时,将地址视为指定的量,而将值视为派生量。
指针用于存储值的地址,因此指针名表示的是地址,指针运算符*
也被成为解除引用运算符,将其应用于指针,可以得到该地址处存储的值。
#include <iostream>
int main()
{
using namespace std;
int updates = 6; // declaare a variable
int * p_updates = &updates ;
cout << "updates value = " << updates << ", " << *p_updates << endl;
cout << "updates address = " << &updates << ", " << p_updates << endl;
*p_updates = *p_updates + 1;
cout << "updates value = " << updates << endl;
}
通过上程序示例可以看出,int变量updates 和指针变量p_updates 类似于一枚硬币的两面。变量updates 表示值,也可以使用取地址运算符&来获取值的地址,而变量p_updates 表示地址,可以使用指针运算符*
来获取地址内存储的值。
且由于p_updates 指向updates,因此*
p_updates和updates 完全等价,可以像使用常规int变量一样使用*
p_updates,比如进行赋值,但是需要注意这会直接修改被指向的变量的值,即updates 。
三、声明指针
指针的声明必须指定指针指向数据的类型。
int * p_updates;
这表明* p_updates的类型是int,p_updates指向int类型,或p_updates的类型是指向int的指针。
也可以说p_updates是指针,而*p_updates是int,而不是指针。如下图所示,指针存储地址。
指针运算符*
的两边空格是可选的:
int *ptr
传统C程序员使用这种格式,这强调*ptr是一个int类型的值。
int* ptr
C++程序员使用这种格式,这强调int*
是一种类型——指向int的指针,在哪里添加空格对于编译器来说没有任何区别。
但是需要注意的是,对每个指针变量名,都需要使用一个*
。
int* p1, p2;
如上例所示程序,是声明了一个指针(p1)和一个int类型的变量(p2)
四、初始化指针
可以在声明语句中初始化指针,此时,被初始化的是指针,而不是它指向的值,以下程序为例,将变量pt(而不是*pt)的值设置为&higgens。
int higgens = 5;
int* pt = &higgens;
五、小心使用指针
在C++中创建指针时,计算机分配用来存储地址的内存,但是不会分配用来存储指针所指向的数据的内存,如果没有为指针赋地址就直接使用,那么将会出现不确定的行为。
long* fellow;
*fellow = 2333;
在上例中,声明了一个指针,指向long类型,但是没有为其赋地址,那么此时指针fellow没有被初始化,它可能有任何值,不管值是什么,程序都会将它解释为存储数据2333的地址,这会导致fellow指向的地方很可能不是程序要存储2333数据的地方,这就导致一种难以排查的bug。
所以在对指针使用指针运算符*之前,一定要将指针初始化为一个确定的,适当的地址