修改指针在C++函数中指向的位置



我陷入了修改指针指针的困境。问题是我不明白为什么我的代码有效。我正在尝试做的是修改指针指向函数中指针的位置。然后在我的主函数中访问该值。我尝试了很多次尝试,这是我让它工作的唯一方法。

#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)

最新更新