何时在C++中使用指向指针的指针

When to use Pointer-to-Pointer in C++?

本文关键字:指针 C++ 何时      更新时间:2023-10-16

我想知道我们在C++中什么时候使用指针对指针,为什么我们需要指向指针?我知道当我们指向一个指针时,这意味着我们将变量的内存地址保存到内存中,但我不知道为什么我们需要它?我还看到了一些例子,在创建矩阵时总是使用指针到指针!但是为什么矩阵可能需要指针对指针呢?

何时在C++中使用"指向指针"?

我认为最好不要在C++中使用它。理想情况下,在处理C API或一些遗留的东西时,您只需要使用它,这些东西仍然与C API相关或在设计时考虑到了C API。

由于C++语言的特性和附带的标准库,指针对指针已经过时了。当你想传递一个指针并编辑函数中的原始指针时,你有引用,对于像指向字符串数组的指针这样的东西,你最好使用std::vector<std::string>。这同样适用于多维数组、矩阵等等,C++有一种比隐指针到指针更好的方法来处理这些事情。

如果要更改作为函数参数传递给函数的变量的值,并在该函数之外保留更新后的值,则需要指向该变量的指针(单指针)。

void modify(int* p)
{
*p = 10;
}
int main()
{
int a = 5;
modify(&a);
cout << a << endl;
}

现在,当您想更改作为函数参数传递给函数的指针的值时,您需要指向指针的指针。

简单地说,当您希望在函数调用之外保留(或保留对内存分配或分配的更改)时,请使用**。(所以,用双指针参数传递这样的函数。)

这可能不是一个很好的例子,但将向您展示基本用途:

void safe_free(int** p) 
{ 
free(*p); 
*p = 0; 
}
int main()
{
int* p = (int*)malloc(sizeof(int));
cout << "p:" << p << endl;
*p = 42;
safe_free(&p);
cout << "p:" << p << endl;
}

当我们想要更改它所指向的指针的地址时,我们基本上需要指针对指针。非常好的例子是链表的情况,当我们试图在开头插入值时,我们将指针对指针发送到头节点。粘贴在下面的代码段。

int main()
{
/* Start with the empty list */
struct node* head = NULL;

/* Use push() to construct below list
1->2->1->3->1  */
push(&head, 1);
push(&head, 2);
.....
....
}

/* Given a reference (pointer to pointer) to the head
of a list and an int, push a new node on the front
of the list. */
void push(struct node** head_ref, int new_data)
{
/* allocate node */
struct node* new_node = (struct node*) malloc(sizeof(struct node));
.....
.....
}

这基本上是因为,比如说一个指针最初指向一个内存位置0X100,我们想把它改为指向其他位置,比如0X108。在这种情况下,将传递指针到指针。

你可能以前见过int main(),你见过这个吗:

int main(int argc, char** argv)

argv实际上是一个双指针,它实际上不是双指针,但它是指向指针数组的指针,每个指针指向与命令行参数相关的字符数组。

这不是最好的例子,因为你可能想要一个更实际的例子。我会写一个更好的例子并编辑我的帖子:)

编辑:

如果您熟悉类和虚拟函数,那么您可能还知道,任何具有虚拟函数的类都会自动获得_vftp成员变量。

_vftp成员是指向虚拟函数的所有函数指针列表的指针。它插入在结构的最开始。如果您按照以下方式创建了一个新对象:

class myclass
{
public:
//void *_vftp; this is where the _vftp member gets inserted automatically
virtual void vfunc1();
};
void myclass::vfunc1() {printf("yay");}
void main() {
myclass *pMyObject = new myclass();
}

在实例化myclass时,_vftp被添加到对象结构中,它是第一个变量。因为pMyObject是指向内存中此结构的指针,所以*pMyObject等同于_vftp。

因为_vftp是指向虚拟函数指针数组的指针,所以*_vftp等于vfunc1(函数指针)。

这意味着,如果我们两次取消引用pMyObject,并调用它,我们将调用vfunc1():

typedef (void* (__thiscall* fnVFunc1))(void);
((fnVFunc)**pMyObject)();

虽然这不是双指针的真正用途,但这是应用它们的一个主要示例。双指针最常见的地方是黑客攻击和逆向工程,在那里你通常需要在内存中找到一个指针,并改变它指向的任何东西

在处理C库的任何时候。对于C中的同一个问题,有两个常见的答案:

首先,任何时候你想要双下标数组,比如:

int main(int argc, char** argv) 

第二,只要您想要函数的另一个返回值。libgit2中有许多函数这样做是因为它们希望返回一个有意义的错误类型,而不仅仅是null,例如git_branch_create中的第一个参数。

当然,您可以返回一个两项struct,但这通常是额外的两行代码。事实上,指针对指针允许您将指针直接写入它所在的结构中。

在C++中,只要存在合适的C++数据类型,就应该避免直接使用指针,我的libgit2示例也包含在C++的异常中,但是。。

你不能从大多数高级语言中调用C++,所以如果你正在编写一个库,你想用Perl、Python和C++来使用,那么你就用C.来编写它

假设您想在C++中实例化一个对象。。。

MyClass * obj = new MyClass();

您必须这样做,因为new会返回一个指向动态内存中已分配对象的指针。以下是错误的:

MyClass obj = new MyClass(); // wrong. 'new' returns a pointer.

假设您想要一组对象。。。

MyClass ** objArray = new MyClass*[10];