Skip to content

Latest commit

 

History

History
105 lines (71 loc) · 4.74 KB

File metadata and controls

105 lines (71 loc) · 4.74 KB

五、指针

指针是一个变量,包含另一个变量的内存地址,称为指针对象

创建指针 s

指针被声明为任何其他变量,除了在数据类型和指针名称之间放置一个星号(*)。使用的数据类型决定了它将指向哪种类型的内存。

int* p; // pointer to an integer
int *q; // alternative syntax

指针可以指向相同类型的变量,方法是在该变量前面加上一个“与”号,以便检索其地址并将其分配给指针。与号被称为地址运算符(&)。

int i = 10;
p = &i; // address of i assigned to p

取消引用指针

上面的指针现在包含了整型变量的内存地址。引用指针将检索这个地址。要获得存储在该地址中的实际值,指针必须以星号为前缀,称为解引用操作符(*)。

std::cout << "Address of i: " <<  p; // ex. 0017FF1C
std::cout << "Value of i: "   << *p; // 10

当写入指针时,使用相同的方法。如果没有星号,指针将被分配一个新的内存地址,如果有星号,指针所指向的变量的实际值将被更新。

p = &i;  // address of i assigned to p
*p = 20; // value of i changed through p

如果创建了第二个指针并赋予了第一个指针的值,那么它将获得第一个指针的内存地址的副本。

int* p2 = p; // copy of p (copies address stored in p)

指向一个指针

有时,拥有一个可以指向另一个指针的指针会很有用。这是通过用两个星号声明一个指针,然后给它分配它将引用的指针的地址来实现的。这样,当存储在第一指针中的地址改变时,第二指针可以跟随该改变。

int** r = &p; // pointer to p (assigns address of p)

引用第二个指针现在给出了第一个指针的地址。解引用第二个指针给出变量的地址,再次解引用它给出变量的值。

std::cout << "Address of p: " << r;   // ex. 0017FF28 std::cout << "Address of i: " << *r;  // ex. 0017FF1C std::cout << "Value of i: "   << **r; // 20

动态分配

指针的主要用途之一是在运行时分配内存——所谓的动态分配 。在迄今为止的例子中,程序只有在编译时为变量声明的那么多可用内存。这被称为静态分配。如果在运行时需要任何额外的内存,new操作符有可以使用。该运算符允许动态分配内存,内存只能通过指针访问。new操作符将原始数据类型或对象作为它的参数,它将返回一个指向分配的内存的指针。

int* d = new int; // dynamic allocation

关于动态分配,需要知道的一件重要事情是,当不再需要时,分配的内存不会像程序内存的其余部分一样被释放。相反,它必须用关键字delete手动释放。这允许您控制动态分配对象的生存期,但也意味着一旦不再需要它,您就要负责删除它。忘记删除已经用new关键字分配的内存将会给程序带来内存泄漏,因为这些内存将会一直被分配,直到程序关闭。

delete d; // release allocated memory

空指针

当指针没有被分配给有效地址时,它应该被设置为零。这样的指针叫做空指针 。这样做将允许您检查指针是否可以被安全地取消引用,因为有效的指针永远不会为零。

例如,尽管前一个指针已经释放了它的内存,但它存储的地址仍然指向一个现在不可访问的内存位置。试图取消引用这样的指针将导致运行时错误。为了帮助防止这种情况,应该将删除的指针设置为零。请注意,尝试删除已经删除的空指针是安全的。但是,如果指针没有设置为零,再次尝试删除它将导致内存损坏,并可能使程序崩溃。

delete d;
d = 0; // mark as null pointer
delete d; // safe

由于您可能不总是知道一个指针是否有效,所以每当一个指针被取消引用时都应该进行检查,以确保它不为零。

if (d != 0) { *d = 10; } // check for null pointer

常量NULL也可以用来表示空指针。在 C++ 中,NULL通常被定义为零,选择使用哪一个是个人喜好的问题。该常量在 stdio.h 标准库文件中定义,该文件包含在 iostream 中。

#include <iostream>
// ...
if (d != NULL) { *d = 10; } // check for null pointer

C++11 引入了关键字 nullptr 来区分 0 和空指针。使用 nullptr 的优点是,与 NULL 不同,它不会隐式转换为整数类型。文本有自己的类型 nullptr_t,它只能隐式转换为指针和 bool 类型。

int* p = nullptr; // ok
int  i = nullptr; // error
bool b = nullptr; // ok (false)

nullptr_t mynull = nullptr; // ok