我想知道我们何时在C ++中使用Pointer to Pointer以及为什么我们需要指向指针?我知道当我们指向一个指针时,这意味着我们将变量的内存地址保存到内存中,但我不知道为什么需要它?另外我看到一些例子总是使用Pointer-to-pointer来创建 Matrix !但为什么Matrix可能需要Pointer to Pointer?
答案 0 :(得分:6)
何时在C ++中使用指针指针?
我认为最好永远不要在C ++中使用它。理想情况下,在处理C API或一些遗留的东西时,您只会必须使用它,仍然与C API相关或设计C / API。
指针指针几乎已被C ++语言功能和附带的标准库淘汰。你有想要传递指针和编辑函数中原始指针的时间的引用,对于像指向字符串数组的指针这样的东西你最好使用std::vector<std::string>
。这同样适用于多维数组,矩阵等等,C ++有更好的方法来处理这些事情,而不是指针的神秘指针。
答案 1 :(得分:1)
你之前可能已经看过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 :(得分:1)
如果要将传递给函数的变量值更改为函数参数,并在该函数外部保留更新值,则需要指向该变量的指针(单指针)。
void modify(int* p)
{
*p = 10;
}
int main()
{
int a = 5;
modify(&a);
cout << a << endl;
}
现在,当您想要将传递给函数的指针值更改为函数参数时,需要指向指针的指针。
简单来说,如果要在函数调用之外保留(或保留更改)Memory-Allocation或Assignment,请使用**
。 (所以,用双指针arg传递这样的函数。)
这可能不是一个很好的例子,但会向您展示基本用途:
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;
}
答案 3 :(得分:1)
当我们想要改变它所指向的指针的地址时,我们基本上需要指向指针。一个非常好的例子是链表的情况,当我们尝试时,我们发送一个指针指向头节点的指针在开头插入一个值。代码片段粘贴在下面。
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。 在这种情况下,传递指向指针的指针。
答案 4 :(得分:1)
任何时候您都在处理C库。 C中同一个问题有两个常见的答案:
首先,任何时候你想要双下标数组,如:
int main(int argc, char** argv)
其次,任何时候你想要一个函数的另一个返回值。 libgit2中有许多函数可以执行此操作,因为它们希望返回有意义的错误类型,而不仅仅是null
,例如git_branch_create中的第一个参数。
当然,您可以返回两个struct
项,但这通常需要两行代码。实际上,指向指针的指针允许您将指针直接写入它所居住的结构中。
在C ++中,只要存在合适的C ++数据类型,就可以避免直接使用指针,而我的libgit2示例包含在C ++的例外中,但是......
你不能从大多数高级语言中调用C ++,所以如果你要编写一个你想要的库,比如Perl,Python和C ++,那么你用C语言编写它。
答案 5 :(得分:0)
假设你想在C ++中实例化一个对象......
MyClass * obj = new MyClass();
您必须这样做,因为new
返回指向动态内存中已分配对象的指针。以下是错误的:
MyClass obj = new MyClass(); // wrong. 'new' returns a pointer.
假设你想要一个对象数组......
MyClass ** objArray = new MyClass*[10];