指针初始化(C++)详解

请记住,指针被设计为指向特定数据类型的对象。当使用一个地址初始化指针时,它必须是指针可以指向的一个对象的地址。

例如,下面的 pint 定义是合法的,因为 myValue 是一个整数:

int myValue;
int *pint = & myValue;

以下语句也是合法的,因为 ages 是一个整数数组:

int ages[20];
int *pint = ages;

但是下面的 pint 定义就是非法的,因为 myFloat 不是 int:

float myFloat;
int *pint = &myFloat; //非法

指针可以与其他相同类型的变量在相同的语句中定义。以下声明定义了一个整型变量 myValue,然后定义了一个指针 pint,该指针使用 myValue 的地址进行初始化:

int myValue,*pint = &myValue;

下面的语句定义了一个数组 readings 和一个指针 maker,maker 指针使用了 readings 数组中第一个元素的地址进行初始化:

double readings[50], *marker = readings;

当然,一个指针只能用已定义对象的地址来初始化。以下语句是非法的,因为使用了一个并不存在的对象地址初始化 pint:

int *pint = &myValue; // 非法
int myValue;

尚未被初始化的局部指针变量并未保存一个有效的地址,如果尝试使用这样的指针,则将导致执行时错误。旧版本 C++ 中的惯例是,将地址 0 分配给当前未指向一个有效内存位置的指针。

int *ptrToint = 0;
double *ptrToDouble = 0;

在大多数计算机中,用户程序不能访问地址为 0 的内存,因为它被操作系统数据占用。这使得 0 成为指示无效内存位置值的安全选择。

许多头文件(包括 iostream、fstream 和 cstdlib)定义了一个名为 NULL 的常量,代表指针值 0。因此,假设已经包含了这些头文件之一,那么上面的代码就可以写成以下形式:

int *ptrToint = NULL;
float *ptrTofloat = NULL;

许多人更喜欢后面这种形式,因为 NUL L被非常清晰地确认代表地址 0,而不是整数 0。无论如何,值为 0 的指针也称为空指针。C++11 定义了关键字 nullptr 来指示一个无效的内存地址:

int *ptrToint = nullptr;
double *ptrToDouble = nullptr;

可以使用测试是否相等的运算符 != 和 == 来测试指针 p 是否和 0、NULL 或 nullptr 相等,以确定它是否指向了一个有效的地址,示例如下:

if ( p ! = nullptr ) { // 使用指针 P... }
if ( p != NULL ) { // 使用指针 P"... }
if ( p != 0 ) { // 使用指针 P... }

指针只能在被判断不为0的情况下使用,所以,以上所有测试都等同于以下测试:

if (p) { // 使用指针 P... }

在 C++ 11 中,在变量定义的末尾放置一对空的大括号 {},即可初始化变量为其默认值。数字类型(例如 int、long 和 double)的默认值是 0,而指针类型的默认值则是 nullptr。因 此,以下定义语句:

int mylnt = 0;
double myDouble = 0.0;
int *ptrToInt = nullptr;

与以下语句是等价的:

int mylnt = 0;
double myDouble = 0.0;
int *ptrToInt = nullptr;

能够快速检查指针是否已经分配了一个正确的值,这是很重要的。出于这个理由,指针应该始终被初始化或分配一个紧邻其定义位置的值。此外,除非指针将离开作用域或程序将终止,否则,不再指向一个有效位置的指针应该分配一个 nullptr 值。