在C++中什么时候需要使用指向指针的指针?

22

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


可能会有类似的原因,你想要指向一个整数。 - user253751
类似:https://stackoverflow.com/q/22193460 - djvg
6个回答

12
何时在C ++中使用指向指针的指针? 我认为最好永远不要在C ++中使用它。理想情况下,您只需要在处理与C API相关或仍然考虑C API的遗留问题时使用它。 指向指针的指针已经被C ++语言特性和相应的标准库所取代。当您想要传递指针并在函数中编辑原始指针时,您可以使用引用,并且对于诸如字符串数组的指针等内容,最好使用std :: vector 。对于多维数组,矩阵等等,C ++有比加密指针更好的处理方式。

11

当你想要改变传递给函数的变量的值,并保留该函数之外的更新后的值时,你需要该变量的指针(单指针)作为函数参数。

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;
}

这是一个很好的例子,因为一些编码标准不鼓励使用非静态引用。 - user3528438
2
我会对这个例子进行反向操作:void safe_free(int**p) { free(*p); *p = 0; } - Jarod42
@Jarod42 好的例子 - CreativeMind
2
代码有误。你必须将int**传递给safe_free(),但你正在传递int* - doubleE
@Mediocre是正确的,你应该将这一行更新为“example safe_free(&p);”。 - rca

6

当我们想要更改指针所指向的地址时,基本上需要使用指向指针的指针。一个非常好的例子就是链表的情况,当我们尝试在开头插入值时,我们会发送一个指向指针的指针到头节点。以下是代码片段:

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。在这种情况下,需要传递指向指针的指针。


3

你可能之前见过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)();

虽然双指针并非真正的用途,但这是应用它们的一个典型例子。最常见的双指针使用场景在黑客和逆向工程中,通常需要在内存中查找指针并修改其指向的内容。


2
任何时候涉及到 C 库时,处理同一个问题时有两个常见答案:
首先,每当您需要双下标数组时,例如:
int main(int argc, char** argv) 

其次,当你希望从函数中得到另一个返回值时,例如在git_branch_create的第一个参数中,许多libgit2中的函数都这样做,因为它们希望返回有意义的错误类型,而不仅仅是null
当然,你可以返回一个两个项的struct,但这通常需要额外的两行代码。实际上,指向指针的指针允许你直接将指针写入一个将要存在的结构中。
在C++中,如果合适的C++数据类型存在,你应该避免直接使用指针。我的libgit2示例被C++的异常所替代,但是...
大多数高级语言无法调用C++,因此,如果你想编写一个库,使其在Perl、Python和C++中可用,那么你需要用C来编写它。

0

假设你想在C++中实例化一个对象...

MyClass * obj = new MyClass();

你必须这样做,因为new返回指向动态内存中分配的对象的指针。以下方法是错误的:
MyClass obj = new MyClass(); // wrong. 'new' returns a pointer.

假设你想要一个对象数组...

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

1
这是错误的。new MyClass*[10] 给你一个指针数组,而不是对象数组。它也是一个未初始化指针的数组。至少写成 new MyClass*[10]() 来获取一个包含 10 个空指针的数组,或者更好的方法是使用 std::vector<MyClass> - MSalters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接