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

时间:2015-03-07 02:19:01

标签: c++ pointers

我一直坚持修改指针指针。问题是我不明白为什么我的代码有效。我要做的是修改指针指向函数的位置。然后在我的main函数中访问该值。我尝试了很多尝试,这是我开始工作的唯一方法。

#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函数的位置而不是主要的?为什么我不必在函数中使用&?我似乎无法找到一个我能在互联网上理解的解释,我想知道是否有人可以为我解释这个?

3 个答案:

答案 0 :(得分:7)

注意:这些内存地址仅用于说明。

内存布局

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函数中使用不同的语法。

  

另外,为什么我不必使用&amp;在功能?

main函数中,变量ppint的类型为int**(即指向指针的指针),而p的类型为int*。您无法执行ppint = p;,因为它们是不同的类型。如果删除一个间接级别,这可能更容易看到。例如:

int* pMyInt = NULL;
int myInt = 3;

我认为这是非常自我解释的,这是行不通的(即,它们是不同的类型)。

pMyInt = myInt;

但是,您可以使用myInt运算符取&的地址,这会导致指向int的指针(即int*),因为此类型与pMyInt现在可以进行任务。

pMyInt = &myInt;

答案 1 :(得分:5)

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; < / p>

在该行之后,您已删除n,但您没有更改其值,因此值保持不变,除非已访问并修改了某些内容。

在删除它之后仍然保留n值的原因被认为是未定义的行为。

答案 2 :(得分:3)

指针已经很难处理,你没有必要让它变得更糟。这也有效:

#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的指针,这是仍然通过引用传递,称为pass by value,因为你传递了一个指针(Thanks Kirk)