C++中“*&”和“**&”的含义

98

我在函数声明中多次发现这些符号,但不知道它们的含义。

例子:

void raccogli_dati(double **& V, double **p, int N) { 
  int ultimo = 3; 
  V = new double * [N/2]; 
  for(int i=0; i < N/2; i++) { 
    V[i] = new double[N/2], std :: clog << "digita " << N/2 - i
                 << " valori per la parte superiore della matrice V: "; 
    for(int j=i; j < N/2; j++) 
      std :: cin >> V[i][j], p[ultimo++][0] = (V[i][j] /= sqrt(p[i][0]*p[j][0]));
  } 
  for(int i=1; i < N/2; i++) 
    for(int j=0; j < i; j++) 
       V[i][j] = V[j][i];
}

在实际的代码或书籍中?对我来说,它只是一般函数的符号表示法。其中一个返回单个指针,另一个返回指向指针的指针。 - Mr. Shickadance
这些是指针的引用。 - Alexandre C.
2
这个网站可能对你有所帮助。 - JW.ZG
8个回答

141

这是通过引用传递参数。因此,在第一种情况下,您通过引用获取指针参数,因此您对指针值所做的任何修改都会在函数外反映出来。第二个与第一个类似,唯一的区别是它是双重指针。请参见以下示例:

void pass_by_value(int* p)
{
    //Allocate memory for int and store the address in p
    p = new int;
}

void pass_by_reference(int*& p)
{
    p = new int;
}

int main()
{
    int* p1 = NULL;
    int* p2 = NULL;

    pass_by_value(p1); //p1 will still be NULL after this call
    pass_by_reference(p2); //p2 's value is changed to point to the newly allocate memory

    return 0;
}

28

第一个是指针的引用,第二个是指向指针的指针的引用。另请参阅有关指针和引用之间差异的常见问题解答

void foo(int*& x, int**& y) {
    // modifying x or y here will modify a or b in main
}

int main() {
    int val = 42;
    int *a  = &val;
    int **b = &a;

    foo(a, b);
    return 0;
}

5
我知道我本不应该这样做,但我还是点了赞,因为它包含一个指针-指针-引用-关于生命意义的影射。但我认为我们离“深思”还有几年的路要走。 - corlettk
在使用 **& 的情况下,我需要检查其中一个指针是否为 NULL 吗? - undefined

20

这是通过引用传递指针而不是值。例如,这允许在函数中更改指针(而不是指向的对象),以便调用代码可以看到更改。

对比:

void nochange( int* pointer ) //passed by value
{
   pointer++; // change will be discarded once function returns
}

void change( int*& pointer ) //passed by reference
{
   pointer++; // change will persist when function returns
}

9

int* 是指向 int 的指针,因此 int*& 必须是指向指向 int 的指针的引用。同样地,int** 是指向指向 int 的指针的指针,因此 int**& 必须是指向指向指向 int 的指针的引用。


1
我理解它们的字面意思,你能写一个例子更有效地说明它们之间的区别吗? - Sheldon

7

*&表示通过引用接收指针。这意味着它是传递参数的别名。因此,它会影响传递的参数。

#include <iostream>
using namespace std;

void foo(int *ptr)
{
    ptr = new int(50);    // Modifying the pointer to point to a different location
    cout << "In foo:\t" << *ptr << "\n"; 
    delete ptr ;
}

void bar(int *& ptr)
{
    ptr = new int(80);    // Modifying the pointer to point to a different location
    cout << "In bar:\t" << *ptr << "\n"; 
    // Deleting the pointer will result the actual passed parameter dangling
}
int main()
{
    int temp = 100 ;
    int *p = &temp ;

    cout << "Before foo:\t" << *p << "\n";
    foo(p) ;
    cout << "After foo:\t" << *p << "\n";

    cout << "Before bar:\t" << *p << "\n";
    bar(p) ;
    cout << "After bar:\t" << *p << "\n";

    delete p;

    return 0;
}

输出:

Before foo: 100
In foo: 50
After foo:  100
Before bar: 100
In bar: 80
After bar:  80

7
通常,你可以从右到左阅读变量声明。因此,在 int *ptr; 的情况下,它表示你有一个指向整数变量 int 的指针 *。当它被声明为 int **ptr2; 时,它是一个指向指针变量的指针变量 *,该指针变量又指向一个整数变量 int,这与 "(int *)* ptr2;" 相同。
现在,按照语法声明 int*& rPtr;,我们说它是一个引用 &,它指向一个指向类型为 int 的变量的指针 *。最后,你也可以将这种方法应用于 int**& rPtr2;,这意味着它表示对指向指针变量的指针 * 的引用 &,该指针变量再指向一个指针变量 *,该指针变量最终指向一个整数 int

3
从右到左阅读声明可以加快理解速度,也能解释为什么对于那些通常从左到右阅读的人来说,C++ 构造的解释有时会很困难。对于这个提示点赞,+1。 - XavierStuvw

4
为了理解这些短语,让我们来看一些事情:
typedef double Foo;
void fooFunc(Foo &_bar){ ... }

这就是通过引用传递双精度浮点数的方法。

typedef double* Foo;
void fooFunc(Foo &_bar){ ... }

现在正在通过引用传递指向double的指针。

typedef double** Foo;
void fooFunc(Foo &_bar){ ... }

最后,它是通过引用传递指向双精度的指针的指针。如果您按照这样的typedef思考,您将理解&和*的正确顺序以及其含义。


2

这个 *& 在理论上和实践中都是可能的,并被称为指针变量的引用,它的作用类似。这个 *& 组合在函数参数中用于“传递”类型定义。与 ** 不同,也可用于声明双重指针变量。
参数传递分为值传递、引用传递和指针传递。 关于“传递”类型的答案有很多种。然而,我们需要了解这个主题的基础知识。

引用传递 --> 通常在传递到函数时操作已创建的变量引用,例如fun(int &a);

指针传递 --> 操作已初始化的“指针变量/变量地址”传递到函数中,例如fun(int* a);

auto addControl = [](SomeLabel** label, SomeControl** control) {
    *label = new SomeLabel;
    *control = new SomeControl;
    // few more operation further.
};

addControl(&m_label1,&m_control1);
addControl(&m_label2,&m_control2);
addControl(&m_label3,&m_control3);

在上述例子中(这是我遇到的真实问题),我试图从lambda函数中初始化几个指针变量,为此我们需要通过双指针传递它,以便在lambda内部的所有使用中对指针进行解引用+在将指针传递给接受双指针的函数时,您需要传递指向指针变量的引用。
因此,使用相同的指针变量引用,*&这种组合有所帮助。以下是我上面提到的相同示例的方式。
auto addControl = [](SomeLabel*& label, SomeControl*& control) {
        label = new SomeLabel;
        control = new SomeControl;
        // few more operation further.
    };

addControl(m_label1,m_control1);
addControl(m_label2,m_control2);
addControl(m_label3,m_control3);

在这里,您可以看到无需解除引用,也不需要在传递函数时传递指针变量的引用,因为当前的按类型传递已经是指针的引用。

希望这可以帮助您 :-)


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