【问题标题】:C++ casting static two-dimensional double array to double**C ++将静态二维双精度数组转换为双精度**
【发布时间】:2013-04-02 14:13:28
【问题描述】:

我的程序中有这样的矩阵:

double m[3][4] = 
    {
        {2, 4, 5, 7},
        {4, 5, 1, 12},
        {9, 12, 13, -4}
    };

我想将其转换为 double** 类型。

我已经尝试过简单的double** a = (double**)m;,但它不起作用(当我尝试读取任何值时,我得到“访问冲突读取位置 0x00000000。”,这意味着我正在尝试从 @987654324 读取@地址。

我找到了几乎可行的解决方案:

double *b = &m[0][0];
double **c = &b;

当我阅读字段c[0][any]时它有效 但是当我尝试从字段c[1][0] 中读取值时,会出现同样的 NULL 地址读取问题。

double m[3][4] 数组转换为类型double** 的正确方法是什么?

编辑: 你说那是不可能的。所以我会稍微改变一个问题。如何将二维双精度数组作为参数传递给函数?我的函数有原型:

void calculate(double **matrix, int n); //where matrix size is always n by n+1 

而且它与动态分配的数组一起工作得很好。我怀疑让它工作的唯一方法是分配新的动态数组并一个接一个地复制原始静态数组......

【问题讨论】:

  • 铸造不会使这项工作。 double ** 需要一个指向双精度指针的指针,而这不是你所拥有的。您可以可能使用double * 并明确传递数组维度。
  • 数组数组和指向指针的指针不是一回事。内存中的布局不匹配,因此一个不能用于另一个。
  • 使用 Vaughn Cato 提出的技术。如果它需要一个double**,你需要给它一个double**,而不是一个二维数组。
  • 您的calculate 函数需要一个指向array指针。你的问题是你没有那个。您的解决方案是创建它。阅读 Vaughn Cato 的回答。

标签: c++ pointers casting double


【解决方案1】:

你不能。

符号double** 指的是一个指针数组。你没有指针数组,你有一个双精度数组。

【讨论】:

    【解决方案2】:

    您不能只转换数组。你将不得不创建这样的东西:

    double m[3][4] = 
        {
            {2, 4, 5, 7},
            {4, 5, 1, 12},
            {9, 12, 13, -4}
        };
    
    double *marray[3] = {m[0],m[1],m[2]};
    calculate(marray,3);
    

    或者你可以使用循环:

    const size_t n = 3;
    double *marray[n];
    for (size_t i=0; i!=n; ++i) {
        marray[i] = m[i];
    }
    calculate(marray,n);
    

    【讨论】:

    • 这对我来说行不通。数组可能有大小,例如 100x100。而且我不会在我的代码中写{m[0],m[1],m[2], ..., m[99]}; :)
    • @gogowitczak:在这种情况下,您可以使用循环(答案已更新)。
    • 没那么简单。我想array 可能具有在编译时未知的不同大小,也就是说,n 不是编译时间常数。因此marray 必须是动态分配的。这可能很好,但如果您想避免动态分配,请使用我在回答中解释的模板。
    【解决方案3】:

    当你写作时

    double m[3][4] 
        {
            {2, 4, 5, 7},
            {4, 5, 1, 12},
            {9, 12, 13, -4}
        };
    

    编译器实际上创建了一个双精度数组,就像你写的一样

    double _m[] = {2, 4, 5, 7, 4, 5, 1, 12, 9, 12, 13, -4};
    

    但是,由于 C/C++ 类型系统,编译器记住了 m 的类型 是double [3][4]。特别是它记得大小 3 和 4。

    当你写作时

    m[i][j]
    

    编译器将其替换为

    _m[i * 4 + j];
    

    4 来自double [3][4] 中的第二个大小。)例如, m[1][2] == 1_m[1 * 4 + 2] == _m[6] == 1 也是如此。

    正如其他人所说,double** 是一种不同的类型,它不携带 大小与它。将double** a 视为 3 x 4 矩阵、a[0]a[1]a[2] 必须是指向double(即double*)的指针,指向 对应行的第一个元素。您可以通过

    double* rows[] = { &m[0][0], &m[1][0], &m[2][0] };
    double** a = &rows[0];
    

    简单的转换不会创建上面的变量rows。让我介绍其他 定义rows的替代(但等效)方法

    double* rows[] = { &m[0][0], &m[0][0] + 4, &m[0][0] + 2 * 4};
    double* rows[] = { &_m[0], &_m[4], &_m[2 * 4]};
    

    如您所见,只需要第二种尺寸(即4)。一般来说,对于 多维数组,除第一个之外的所有大小都是必需的。为了这 推理一维数组

    double x[4] = { 1, 2, 3, 4 };
    

    可以隐式转换为double*

    double* y = x;
    

    利用这个事实我们也可以写

    double* rows[] = { _m, _m + 4, _m + 2 * 4};
    

    确实,_m 被转换为指向m[0]double*。然后,在_m + 4_m 被转换为指向 m[0]double* 和指向这个指针 它已添加4。因此,_m + 4 是第四个双精度指针 _m[0],即_m[4]等等。

    到目前为止,我已经解释了为什么不能将 double [3][4](或任何其他大小)转换为 double**。现在,我将在您的特定情况下展示如何定义计算。

    template <int N>
    void calculate(double (&m)[N][N+1]) {
       // use m as a double[N][N+1]
    }
    

    你打电话

    calculate(m);
    

    编译器会为你推导出大小N。一般来说(即当第二维不是N + 1时)你可以写

    template <int N, int M>
    void calculate(double (&m)[N][M]) {
       // use m as a double[N][M]
    }
    

    【讨论】:

      【解决方案4】:

      如果您始终使用数组(无指针)进行初始化,并且能够避免在计算函数中使用指针,您可以考虑使用以下选项,该选项使用模板的大小扣除。

      template<int m, int n>
      void doubleFunc(double (&mat)[m][n])
      {
          for (auto i = 0; i < m; i++)
          {
              for (auto j = 0; j < n; j++)
              {
                  std::cout << mat[i][j] << std::endl;
              }
          }
      }
      

      它在我的快速测试中起作用。

      double m[3][4] = 
      {
          {2, 4, 5, 7},
          {4, 5, 1, 12},
          {9, 12, 13, -4}
      };
      
      doubleFunc(m);
      

      【讨论】:

        【解决方案5】:

        您可以将二维数组作为函数参数传递:

        void calculate(double matrix[][y], int n);

        【讨论】:

          【解决方案6】:

          在可变长度数组符合 C++ 标准之前,您的选择包括:

          • 如果您的编译器支持可变长度数组作为扩展,您可以通过函数声明(例如void foo(std::size_t n, double a[][n+1]))传递它们。请注意,编译器可能要求在使用 n 或需要一些特殊语法的参数声明之前传递 n
          • 您可以传递double * 并在函数中手动进行索引运算:void foo(std::size_t n, double *a) { … a[row*(n+1) + column] … }
          • 您可以通过在其访问器函数中执行索引算术来创建一个实现可变长度数组的类。
          • 您可以为n 指向double 的指针分配空间,用指向数组每一行的指针填充这些指针,然后传递空间的地址。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-11-21
            • 2015-09-13
            • 2011-07-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-11-21
            相关资源
            最近更新 更多