题
在什么情况下您可能想要使用多重间接寻址(即,如下所示的指针链) Foo **
)在C++中?
解决方案
@aku 指出的最常见用法是允许对指针参数的更改在函数返回后可见。
#include <iostream>
using namespace std;
struct Foo {
int a;
};
void CreateFoo(Foo** p) {
*p = new Foo();
(*p)->a = 12;
}
int main(int argc, char* argv[])
{
Foo* p = NULL;
CreateFoo(&p);
cout << p->a << endl;
delete p;
return 0;
}
这将打印
12
但是还有其他一些有用的用法,如以下示例所示,可以迭代字符串数组并将它们打印到标准输出。
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
const char* words[] = { "first", "second", NULL };
for (const char** p = words; *p != NULL; ++p) {
cout << *p << endl;
}
return 0;
}
其他提示
IMO 最常见的用法是传递对指针变量的引用
void test(int ** var)
{
...
}
int *foo = ...
test(&foo);
您可以使用双指针创建多维锯齿状数组:
int ** array = new *int[2];
array[0] = new int[2];
array[1] = new int[3];
一种常见的情况是您需要通过 无效的 指向函数的指针,并在该函数内初始化它,并在函数外使用它。如果没有乘法间接寻址,调用函数将永远无法访问已初始化的对象。
考虑以下函数:
initialize(foo* my_foo)
{
my_foo = new Foo();
}
任何调用“initialize(foo*)”的函数都将无权访问初始化的实例 富, ,因为传递给该函数的指针是一个副本。(指针毕竟只是一个整数,而整数是按值传递的。)
但是,如果函数是这样定义的:
initialize(foo** my_foo)
{
*my_foo = new Foo();
}
...它是这样称呼的...
Foo* my_foo;
initialize(&my_foo);
...然后调用者可以通过“my_foo”访问初始化的实例 - 因为它是 地址 传递给“初始化”的指针。
当然,在我的简化示例中,“initialize”函数可以简单地通过 return 关键字返回新创建的实例,但这并不总是适合 - 也许该函数需要返回其他内容。
如果您将指针作为输出参数传递,您可能希望将其传递为 Foo**
并将其值设置为 *ppFoo = pSomeOtherFoo
.
从算法和数据结构部门,您可以使用双重间接来更新指针,这比交换实际对象更快。
一个简单的例子是使用 int** foo_mat
作为二维整数数组。或者你也可以使用指向指针的指针 - 假设你有一个指针 void* foo
并且您有 2 个不同的对象,它们通过以下成员引用它: void** foo_pointer1
和 void** foo_pointer2
, ,通过一个指向指针的指针,您实际上可以检查是否 *foo_pointer1 == NULL
这表明 foo 为 NULL。如果 foo_pointer1 是常规指针,您将无法检查 foo 是否为 NULL。我希望我的解释不会太混乱:)
卡尔:你的例子应该是:
*p = x;
(你有两颗星。):-)
在 C 语言中,惯用语是绝对必需的。考虑以下问题:您希望函数将字符串(纯 C,因此是 char *)添加到指向 char * 的指针数组中。函数原型需要三个间接级别:
int AddStringToList(unsigned int *count_ptr, char ***list_ptr, const char *string_to_add);
我们这样称呼它:
unsigned int the_count = 0;
char **the_list = NULL;
AddStringToList(&the_count, &the_list, "The string I'm adding");
在 C++ 中,我们可以选择使用引用,这会产生不同的签名。但我们仍然需要您在原始问题中询问的两个间接级别:
int AddStringToList(unsigned int &count_ptr, char **&list_ptr, const char *string_to_add);
通常当您将指针传递给函数作为返回值时:
ErrorCode AllocateObject (void **object);
其中函数返回成功/失败错误代码,并使用指向新对象的指针填充对象参数:
*object = new Object;
这在 Win32 的 COM 编程中被大量使用。
这更像是 C 要做的事情,在 C++ 中,您通常可以将这种类型的系统包装到一个类中,以使代码更具可读性。