将指针传递给二维数组 C++

6

我有一个问题已经困扰我很长时间了 - 我有一个作为类成员的固定大小的二维数组。

class myClass
{ 
public:
        void getpointeM(...??????...);
        double * retpointM();

private:

   double M[3][3];

};

int main()
{
     myClass moo;
     double *A[3][3];

     moo.getpointM( A );  ???
     A = moo.retpointM(); ???

} 

我希望将指向矩阵 M 的指针传递到外部。这可能非常简单,但我只是找不到正确的 &* 等组合。

谢谢帮助。

7个回答

9

double *A[3][3];是一个由double *组成的二维数组。你需要的是double (*A)[3][3];

注意,A*A**A都具有相同的地址,只是类型不同。

使用typedef可以简化事情:

typedef double d3x3[3][3];

因为这是C++,所以应该通过引用传递变量,而不是指针:

void getpointeM( d3x3 &matrix );

现在您不需要在类型名称中使用括号,编译器会确保您传递的是正确大小的数组。

你不应该使用引用“因为这是C++”或“只是因为你可以”。只有在它们比其他可用的替代方案更清晰时才使用它们。 - Roger Pate
@Roger:是的,无论如何,在这里使用它是合适的 :v) - Potatoswatter

3
您的意图不够清晰。 getpointeM 应该是做什么的?是返回指向内部矩阵的指针(通过参数),还是返回矩阵的副本?
如果要返回指针,您可以这样做:
// Pointer-based version
...
void getpointeM(double (**p)[3][3]) { *p = &M; }
...
int main() {
  double (*A)[3][3];
  moo.getpointM(&A);
}

// Reference-based version
...
void getpointeM(double (*&p)[3][3]) { p = &M; }
...
int main() {
  double (*A)[3][3];
  moo.getpointM(A);
}

对于retpointM,声明应如下所示

...
double (*retpointM())[3][3] { return &M; }
...
int main() {
  double (*A)[3][3];
  A = moo.retpointM();
}

虽然这段文字很难读懂,但如果您使用typedef名称来定义数组类型,就可以使它变得更加清晰易懂。

typedef double M3x3[3][3];

在这种情况下,上述示例将转换为:
// Pointer-based version
...
void getpointeM(M3x3 **p) { *p = &M; }
...
int main() {
  M3x3 *A;
  moo.getpointM(&A);
}

// Reference-based version
...
void getpointeM(M3x3 *&p) { p = &M; }
...
int main() {
  double (*A)[3][3];
  moo.getpointM(A);
}

// retpointM
...
M3x3 *retpointM() { return &M; }
...
int main() {
  M3x3 *A;
  A = moo.retpointM();
}

0
简短的回答是,您可以将 double * 放在数组的开头:
public:
   double * getMatrix() { return &M[0][0]; }

然而,在类外部,你不能轻易地将double *直接转换为另一个2D数组,至少我没有见过这种模式。

你可以在主函数中创建一个2D数组(double A [3] [3]),并将其传递给getPoint方法,该方法可以将值复制到传入的数组中。这将给你一个副本,这可能是你想要的(而不是原始的可修改数据)。当然,缺点是你必须复制它。


0
在你的main()函数中:
double *A[3][3];

创建一个3x3的double*数组(或指向双精度浮点数的指针)。换句话说,它是9个32位连续内存单元,用于存储9个内存指针。

除非类将被销毁并且您仍然想要访问此信息,否则在main()中不需要复制此数组。相反,您可以简单地返回指向该成员数组开头的指针。

如果您只想返回对内部类成员的指针,则在main()中实际上只需要一个单一指针值:

double *A;

但是,如果您将此指针传递给函数并且需要该函数更新其值,则需要一个双重指针(它将允许函数将真正的指针值返回给调用者:

double **A;

getpointM()函数内部,你可以直接将A指向内部成员变量(M):

getpointeM(double** A)
{
    // Updated types to make the assignment compatible
    // This code will make the return argument (A) point to the
    // memory location (&) of the start of the 2-dimensional array
    // (M[0][0]).
    *A = &(M[0][0]);
}

好像这就是我真正想做的事情 :) 但仍然出现错误:无法将“double [3][3]”转换为“double*”进行赋值。 - Moomin
抱歉我的失误 - 忘记在两行中都添加 **。 - Moomin
2
这对我来说毫无意义。成员被声明为 double M[3][3]。赋值语句 *A = M 简单地无法编译,因为左侧是 double * 而右侧是 double (*)[3]。这些类型不兼容。 - AnT stands with Russia
@AndreyT - 抱歉,是我的错误。我已经更新了代码以使类型兼容。 - LeopardSkinPillBoxHat
我认为你误解了getpointeM的意义(可能是因为OP也不太清楚)。为什么不在你的代码中返回&M[0][0]而不需要参数呢? - Roger Pate
@Roger - 当然,那是有效的。我试图让我的答案与OP所问的保持一致,但你提出的建议肯定更清晰。 - LeopardSkinPillBoxHat

0
class myClass
{ 
public:
        void getpointeM(double *A[3][3])
        {
           //Initialize array here
        }

private:

   double M[3][3];

};

int main()
{
     myClass moo;
     double *A[3][3];

     moo.getpointM( A );
} 

0
将M从私有变为公有。既然你想通过指针访问M,那么M本身就没有封装性了。
struct myClass { 
  myClass() {
    std::fill_n(&M[0][0], sizeof M / sizeof M[0][0], 0.0);
  }
  double M[3][3];
};

int main() {
  myClass moo;
  double (*A)[3] = moo.M;
  double (&R)[3][3] = moo.M;

  for (int r = 0; r != 3; ++r) {
    for (int c = 0; c != 3; ++c) {
      cout << A[r][c] << R[r][c] << ' ';
      // notice A[r][c] and R[r][c] are the exact same object
      // I'm using both to show you can use A and R identically
    }
  }

  return 0;
}

一般来说,我更喜欢使用R而不是A,因为所有的长度都是固定的(如果需要,A可能会指向一个double[10][3]),并且引用通常会导致更清晰的代码。


0
您可能想将处理双精度二维数组的主函数中的代码移动到myClass作为成员函数。这样,您不仅不必处理传递指向该2D数组的指针的困难,而且类外部的代码也不再需要知道您的类如何实现A,因为它们现在将调用myClass中的函数并让其完成工作。例如,如果您稍后决定允许A的可变尺寸,并选择使用vector的vector替换数组,则无需重写任何调用代码即可使其正常工作。

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