在c ++中创建和传递多维数组的优雅方式?

时间:2011-01-11 07:20:20

标签: c++ pointers multidimensional-array

第一个问题:

对于已知维度,我们不需要new / malloc来创建

   const int row = 3;  
   const int col = 2;  
   int tst_matrix[row][col] ={{1,2},{3,4},{5,6}}

但是,将这个二维数组传递给另一个函数并不容易,对吧?因为

   int matrix_process(int in_matrix[][])

是非法的,您必须指定除第一个之外的所有尺寸。如果我需要更改in_matrix的内容,我怎样才能轻松将tst_matrix传递给函数matrix_process?

第二个问题: 用c ++在c ++中创建二维数组的标准方法是什么?我不想在这里使用std :: vector等。 这是我想出的,这是最好的方式吗?

    int **tst_arr = new int*[5];
    int i=0, j=0;

    for (i=0;i<5;i++)
    {
       tst_arr[i] = new int[5];
       for (j=0;j<5;j++)
       {
          tst_arr[i][j] = i*5+j;
       }
    }

此外,如果我将tst_array传递给另一个函数,例如:

     int change_row_col( int **a)       
     {
         .....................
         //check which element is 0
         for (i=0; i<5; i++)
            for(j=0;j<5;j++)
           {
             if (*(*(a+i)+j)==0)  //why I can not use a[i][j] here?
             {
               row[i]=1;
               col[j]=1;              
             }
           }
         .....................
     }

另外,如果我使用(a + i)+ j),结果就不是我想要的。 这是我的完整测试代码:

    #include <iostream>

    using namespace std;

    //Input Matrix--a: Array[M][N]

    int change_row_col( int **a)
    {
     int i,j;
     int* row = new int[5];
     int* col = new int[5];

     //initialization
     for(i=0;i<5;i++)
     {
        row[i]=0;
     }

     for(j=0;j<5;i++)
     {
        col[j]=0;
     }

     //check which element is 0
     for (i=0; i<5; i++)
         for(j=0;j<5;j++)
        {
           if (*(*(a+i)+j)==0)  //why I can not use a[i][j] here?
           {
               row[i]=1;
               col[j]=1;              
           }
        }

     for(i=0;i<5;i++)
       for (j=0;j<5;j++)
       {
            if (row[i] || col[j])    
            {
               *(*(a+i)+j)=0;
            }
       }
     return 1;
 }



int main ()
{
    int **tst_arr = new int*[5];
    int i=0, j=0;

    for (i=0;i<5;i++)
    {
       tst_arr[i] = new int[5];
       for (j=0;j<5;j++)
       {
          tst_arr[i][j] = i*5+j;
       }
    }

  for (i=0; i<5;i++)
  {
    for(j=0; j<5;j++)
    {
       cout<<" "<<tst_arr[i][j];
    }
    cout<<endl;
  }
 change_row_col(tst_arr);

 for (i=0; i<5;i++)
 {
     for(j=0; j<5;j++)
     {
        cout<<" "<<tst_arr[i][j];
     }
     cout<<endl;
 }

   for (i=0;i<5;i++)
   {
      delete []tst_arr[i];
   }
   delete []tst_arr;
 }

6 个答案:

答案 0 :(得分:3)

对于多维数组,所有边界在运行时都是可变的,我所知道的最常见的方法是使用动态分配的一维数组并“手动”进行索引计算。在C ++中,您通常会使用诸如std::vector特化之类的类来管理此数组的分配和释放。

这产生与具有固定边界的多维数组基本相同的布局,并且没有任何实际隐含的开销,因为没有固定边界,任何方法都需要在运行时传递所有条形的一个数组维。

答案 1 :(得分:2)

老实说,我认为最好的想法是避免使用原始C ++数组,而选择类似boost :: multi_array类型的包装类。这消除了原始数组产生的各种奇怪现象(难以将S参数传递给函数,跟踪数组大小的问题等)。

另外,我强烈建议你重新考虑你对std :: vector的立场。它比原始数组更安全,在大多数情况下,确实没有充分的理由在向量上使用动态数组。如果你有C背景,那么值得花时间进行切换。

答案 2 :(得分:1)

1)

template < typename T, size_t Row_, size_t Col_>
class t_two_dim {
public:
    static const size_t Row = Row_;
    static const size_t Col = Col_;
    /* ... */
    T at[Row][Col];
};

template <typename T>
int matrix_process(T& in_matrix) {
    return T::Row * T::Col + in_matrix.at[0][0];
}

2)使用std :: vector。您正在添加一些函数调用(可能在优化的构建中内联),并可能导出一些额外的符号。我认为有很好的理由可以避免这种情况,但是适当的理由是非常罕见的。你有适当的理由吗?

答案 3 :(得分:1)

简单的答案是,用C ++编写它的优雅方式(你标记了C和C ++,但你的代码是C ++ new / delete)是通过创建二维matrix类并传递它(通过引用或const引用)。之后,下一个选项应始终为std::vector(同样,我将根据向量实现矩阵类)。除非你有一个非常令人信服的理由,否则我会避免处理原始的数组数组。

如果你真的需要,但只有你真的需要,你可以完美地使用多维数组,它比使用普通数组稍微麻烦一点。如果所有维度在编译时都是已知的,就像在第一个块中一样,这是一些选项。

const unsigned int dimX = ...;
const unsigned int dimY = ...;
int array[dimY][dimX];
void foo( int *array[dimX], unsigned int dimy ); // [1]
void foo( int (&array)[dimY][dimX] );            // [2]

在[1]中,通过使用pass-by-value语法,数组衰减成指向第一个元素的指针,这意味着指向int [dimX]的指针,这就是你需要传递的指针。请注意,您应该在另一个参数中传递另一个维度,因为函数中的代码将不知道该维度。在[2]中,通过将引用传递给数组,可以修复所有维度并使其已知。编译器将确保您只使用适当大小的数组调用(两个维度重合),因此无需传递额外参数。第二个选项可以模板化以适应不同的大小(所有这些都在编译时已知):

template <unsigned int DimX, unsigned int DimY>
void foo( int (&array)[DimY][DimX] );

编译器将扣除大小(如果真实的数组传递给模板),您将能够在模板中使用DimXDimY 。这使得可以使用具有不同数组大小的函数,只要它们在编译时都是已知的。

如果在编译时不知道维度,那么事情会变得非常混乱,唯一合理的方法是将矩阵封装在类中。基本上有两种方法。第一种是分配单个连续的内存块(正如编译器在之前的情况下所做的那样),然后提供通过二维索引该块的函数。查看第一段中的链接以获得一个简单的方法,即使我在内部使用std::vector而不是原始指针。请注意,使用原始指针需要在销毁时手动管理指针的删除,否则程序将泄漏内存。

另一种方法,就是你在问题的第二部分开始的那个方法是我不惜一切代价避免的方法,并且包括将指针指向一个指向整数的指针。这会使内存管理变得复杂(您需要将delete指针移至必须删除DimY+1指针 - 每个array[i],再加上array),您还需要手动保证在分配期间,所有行包含相同数量的列。可能出错但没有增益的事物数量大幅增加,但实际损失有一些(保持中间指针需要更多内存,运行时性能更差,因为你必须加倍引用,可能更糟糕的数据局部性......

结束语:根据连续的内存块编写一个封装二维对象的类(如果在编译时已知大小,则为数组 - 编写不同编译时间大小的模板 - std::vector if大小直到运行时才知道,指针只有在你有令人信服的理由时才会知道),并传递该对象。任何其他事情往往会使代码复杂化并使其更容易出错。

答案 4 :(得分:1)

我的解决方案使用功能模板:

template<size_t M,size_t N>
void Fun(int (&arr)[M][N])
{
   for ( int i = 0 ; i < M ; i++ )
   {
       for ( int j = 0 ; j < N ; j++ )
       {
           /*................*/
       }
   }
}

答案 5 :(得分:0)

关于你的第一个问题:

如果需要传递可变大小的ND数组,可以按照以下方法定义此类函数。因此,通过这种方式,您可以将所需的大小参数传递给函数。 我已在gcc中对此进行了测试,但确实有效。

2D案例:

void editArray(int M,int N,int matrix[M][N]){

//do something here

}
int mat[4][5];

editArray(4,5,mat);  //call in this way