我陷入了修改指针指针的困境。问题是我不明白为什么我的代码有效。我正在尝试做的是修改指针指向函数中指针的位置。然后在我的主函数中访问该值。我尝试了很多次尝试,这是我让它工作的唯一方法。
#include <iostream>
using namespace std;
void changePP(int **ppint) {
int *n = new int;
*n = 9; //just a value for demonstration purposes
*ppint = n; //THE LINE IN QUESTION
delete n;
}
int main() {
int **ppint = NULL;
int *p = new int;
*p = 4; //another value for demonstrating
ppint = &p;
cout << **ppint << endl;
changePP(ppint);
cout << **ppint << endl;
}
因此,输出是 4,然后在单独的行上是 9。但是,我不确定代码中*ppint = n
行。为什么我必须使用*
来更改 ppint 在 changePP 函数中指向的位置,而不是在主要函数中?另外,为什么我不必在函数中使用&
?我似乎无法在互联网上找到我可以理解的解释,我想知道是否有人可以为我解释这一点?
注意:这些内存地址仅用于说明。
内存布局
0x0A | 4
0x0B | 'p' -> 0x0A // Pointer to the value 4 in location 0x0A
0x0C | 'ppint' -> NULL // Initially a null pointer
执行ppint = &p;
会产生以下内容,因为此处ppint
是位于 0x0C
的指针。
0x0A | 4
0x0B | 'p' -> 0x0A
0x0C | 'ppint' -> 0x0B
至于changePP
函数中的参数,为了减少混淆,我将它称为ppintCopy
。它是一个副本(即一个不同于ppint
的指针),修改它只会修改副本。
0x0D | 'ppintCopy' -> 0x0C // A pointer that points to `ppint`
执行ppintCopy = &n
将修改指针位于0x0D
,这不是指针在main
函数中的位置。但是,引用ppintCopy
(即*ppintCopy
)会产生0X0C
哪个是来自main
函数的指针,因此*ppintCopy = n;
正在更改指针0x0C
指向的位置。
为什么我必须使用 * 来更改 ppint 在 changePP 函数中指向的位置,而不是在主函数中
?
通过上面的插图,我希望它更清楚为什么它在main
中工作,以及为什么你必须在changePP
函数中使用不同的语法。
另外,为什么我不必在函数中使用 &?
在 main
函数中,变量 ppint
的类型为 int**
(即指向指针的指针),p
的类型为 int*
。您无法执行ppint = p;
因为它们是不同的类型。如果删除一个间接级别,这可能更容易看到。例如:
int* pMyInt = NULL;
int myInt = 3;
我认为这是不言自明的,这是行不通的(即,它们是不同的类型)。
pMyInt = myInt;
但是,您可以使用 &
运算符获取myInt
的地址,这将产生指向 int 的指针(即 int*
),并且由于此类型与pMyInt
的类型相同,因此现在可以进行赋值。
pMyInt = &myInt;
ppint; // the variable name
*ppint; // dereference the first layer of pointer
*(*ppint); // dereference the first layer of pointer which points to another pointer that contains a **value**
因此,*ppint = n;
表示指向另一个内存位置的点 ppint
,该位置是分配给n
的位置,或者可以将其重写为*ppint = &n;
在该行之后,您已经删除了n
但您没有更改其值,因此该值保持不变,除非某些内容访问并修改了它。
但是,删除n
后仍保留其值的原因被视为未定义的行为。
已经很麻烦了,你不必让它变得更糟。这也适用于:
#include <iostream>
using namespace std;
void changePP(int *ppint) {
*ppint = 9;
}
int main() {
int p = 4;
int *ppint = &p;
cout << *ppint << endl; // this could be replaced with /*p*/
changePP(ppint); // note you could have replaced this parameter with /*&p*/
cout << *ppint << endl; // this could be replaced with /*p*/
}
让我试着解释一下你的代码在做什么,但请以后不要这样做。按照我展示的方式做
#include <iostream>
using namespace std;
void changePP(int **ppint) {
int *n = new int; // you allocate memory for a single integer (again it is uninitialised)
*n = 9; // the value at the above pointer is now changed to 9
*ppint = n; // here you have just dereferenced a pointer to pointer which gives you a pointer, so in essence you are changing the location in memory where this pointer is pointing and it is now pointing to whatever memory address n was
delete n;
}
int main() {
int **ppint = NULL; // Here you have declared a pointer to pointer which is NULL
int *p = new int; // You can do better here with /*new int(4)*/
*p = 4; // this changes the value that p initially held (which could be anything)
ppint = &p; // reference to a pointer always creates a pointer to a pointer and since that is what ppint is, you are safe here
cout << **ppint << endl; // print the value nested within this pointer
changePP(ppint); // now you call the function with a variable of type pointer to pointer. Note you could have passed &p as parameter here and it would have still worked
cout << **ppint << endl;
}
这个故事的寓意是什么?
将参数v
传递给函数时,
-
&v
将生成指向 v 的指针 -
*v
将取消引用 v,并让您访问v
指向的任何
内容
当v
是函数中的参数时,
-
&v
会将实际对象v
引入函数的范围。这称为按引用传递 -
*v
是一个指向 v 的指针,这仍然是通过引用传递的,称为按值传递,因为你正在传递一个指针(谢谢 Kirk)