1.指针和自由存储空间
计算机程序存储数据时必须跟踪3种基本属性:
1. 信息存储在何处
2. 存储的值是多少
3. 存储的信息是什么类型
另一种策略是:以指针为基础,指针是一个变量,其存储的是值的地址,而不是值本身。
指针与C++基本原理
面向对象编程与传统的过程性编程的区别在于,OOP强调的是在运行阶段(而不是编译阶段)进行决策。运行阶段决策就好比度假时,选择参观哪些景点取决于天气和当时的心情;而编译阶段决策更像不管什么条件下,都坚持预先设定的日程安排。
例如对于数组,编译阶段决策就需要在编译阶段就确定数组的长度,所以我们需要为数组创建尽可能长的长度,而大多数时候,这个长度都是用不完的,会造成内存的浪费。而运行阶段决策就会解决这一问题,在运行阶段根据此时数组需要的长度来决定内存的大小。
关于如何在运行阶段决定数组的长度,C++采用的方法是,使用关键字new来请求正确数量的内存以及使用指针来跟踪新分配的内存的位置。
#include <iostream>
int main()
{
using namespace std;
int updates = 6;
int *p_updates;
p_updates = &updates;
cout << "Values: updates = " << updates;
cout << ", *p_updates = " << *p_updates << endl;
cout << "Addresses : &updates = " << &updates;
cout << ", p_updates = " << p_updates << endl;
//use pointer to change value
*p_updates = *p_updates + 1;
cout << "Now updates = " << updates << endl;
return 0;
}
输出为:
Values: updates = 6, *p_updates = 6
Addresses : &updates = 0x28ff08, p_updates = 0x28ff08
Now updates = 7
Process returned 0 (0x0) execution time : 0.343 s
Press any key to continue.
1.1声明和初始化指针
声明
指针声明必须指定指针指向的数据的类型。因为不同的数据类型所占用的存储空间不一样。
例如下面的两种声明方式:
int *ptr;
将*放在了ptr的前面,强调的是*ptr是一个int类型的值。
int* ptr;
将*放在了int的后面,强调的是int*是一种类型,是指向int的指针。
但是:
int* p1, p2;
将创建一个指针(p1)和一个常规int变量(p2)。对每个指针变量名,都需要使用一个* 。
对于指向不同数据类型的指针,他们的长度是一样的,一般为2个或者4个字节,取决于计算机系统。
初始化
可以在声明语句中初始化指针。在这种情况下,被初始化的是指针,而不是它指向的值。即:
int higgens = 5;
int *pt = &higgens;
将pt(而不是*pt)的值设置为&higgens。
也就是说上面的代码和下面的是等效的:
int higgens = 5;
int *pt;
pt = &higgens;
看下面这个例子:
#include <iostream>
int main()
{
using namespace std;
int i = 6;
int *p_i = &i;
cout << i << endl;
cout << &i << endl;
cout << p_i << endl;
cout << *p_i << endl;
int j = 9;
*p_i = j;
cout << i << endl;
cout << &i << endl;
cout << p_i << endl;
cout << *p_i << endl;
cout << &p_i << endl;
int k = 12;
p_i = &k;
cout << i << endl;
cout << &i << endl;
cout << p_i << endl;
cout << *p_i << endl;
cout << &p_i << endl;
return 0;
}
运行结果是:
6
0x28ff08
0x28ff08
6
0x28ff04
9
0x28ff08
0x28ff08
9
0x28ff04
9
0x28ff08
0x28ff00
12
0x28ff04
Process returned 0 (0x0) execution time : 0.201 s
Press any key to continue.
1.2 指针的危险
在C++中创建指针时,计算机将分配用来存储地址的内存,但不会分配用来存储指针所指向的数据的内存。
一定要在对指针应用解除引用操作符(*)之前,将指针初始化为一个确定的,适当的地址,这是关于使用指针的金科玉律。
例如:
long *fellow;
*fellow = 223333;
这里,fellow是一个指针,但是计算机只为它分配了存储fellow值的内存,没有分配存储fellow所指向的数据即(*fellow)的内存。那么*fellow = 223333将被存储在哪里呢?我们不知道。由于fellow没有初始化,它可能有任何值。不管只是什么,程序都将它解释为存储223333的地址,如果fellow的值恰巧为1200,计算机将把数据存放在223333地址上,即使这恰巧是程序代码的地址。没有初始化的指针所指向的地址很可能并不是所要存储值的地方,这种错误可能会导致一些最隐匿,最难以跟踪的bug。
1.3 指针和数字
指针不是整数。
整数可以执行加减乘除的运算,而指针描述的是位置,将两个地址相乘没有任何意义。因此,不能简单地将整数赋值给指针。
例如:
int *pt;
pt = 0xB8000000;
这是错误的,正确方法是先将整数进行强制类型转换,然后再赋值给指针。如下:
int *pt;
pt = (int*)0xB8000000; //将0XB8000000强制类型转换为指向int的指针
1.4 使用new来分配内存
接下来分析指针如何实现重要的OOP技术——在程序运行时分配内存。