【问题标题】:Is it possible to write a function which can take array of n dimensions?是否可以编写一个可以采用 n 维数组的函数?
【发布时间】:2014-11-14 11:32:58
【问题描述】:

我正在尝试编写一个函数,该函数可以获取任何维度的数组并成功打印数组中的值。但是我无法继续前进,因为我们必须在声明函数时声明除了最左边的所有维度。是否有可能我们可以编写一个可以将数组作为任何维度的输入的通用函数?

例如,函数应该可以取二维数组或三维数组或n维数组,其中n为任意数字。

【问题讨论】:

  • variadic templates 可能是可能的。
  • 您可以以某种方式使用模板,但这会使程序出错,尤其是因为听起来您正在与团队合作。
  • @JoachimPileborg 这取决于生成是随机的还是预定义的;可变参数模板适用于预定义而非随机。
  • 答案似乎也取决于这是 C 还是 C++ 问题,因为我认为 C 中不存在模板。

标签: c++ c


【解决方案1】:

对每个维度和模板使用 recursion(在 C++ 中也是如此),以下可能会有所帮助:

template <typename T>
void print(const T&e)
{
    std::cout << e << " ";
}

template <typename T, std::size_t N>
void print(const T (&a)[N])
{
    std::cout << "{";
    for (const auto& e : a) {
        print(e);
    }
    std::cout << "}" << std::endl;
}

示例用法:

int a[2][3][4];
print(a);

Live example

【讨论】:

  • 这适用于支持 C++11 的编译器。
  • @RaydelMiranda:如果需要,for range 可以写成与 C++03 兼容(一个简单的 print(a[i]); 就可以了)。
  • 您能告诉我怎么做吗?我不知道。
  • @RaydelMiranda: for (std::size_t i = 0; i != N; ++i) { print(a[i]); }
  • 我知道你可以这样写,但同样,你发布的代码只有在编译器支持 c++11 时才能编译。不是评论家,它只是对读者的警告。
【解决方案2】:

如果您将数组编码为一维,然后自己计算单个索引,那么您当然可以让程序表现得好像数组是为可变维数创建的一样。

关于如何做到这一点,我最初的想法是从一个包含您打算使用的每个维度的范围的向量开始。

该向量中的元素数将是您拥有的维度数。

【讨论】:

    【解决方案3】:

    数组作为指向数组元素类型的指针传递给函数,与数组的维数无关。您可以有更多参数来指定维数 n 和一个长度为 n 的数组(另一个),指定每个维中的元素数。请注意,[] 符号只是一种执行指针加法的简洁方式。

    【讨论】:

      【解决方案4】:

      如果您想访问特定元素或对数组进行操作,但如果您想动态创建矩阵,则可以使用指针通过在打印函数中传递维度来访问每个元素。

      既然你有一个定义为int [][]的多维数组,那么 x = y[a][b] 等价于x = *((int *)y + a * NUMBER_OF_COLUMNS + b);

      查看此帖子了解更多详情:How to use pointer expressions to access elements of a two-dimensional array in C?

      所以,如果你想打印整个矩阵或访问任何特定元素,你可以这样做:

      #include <iostream>
      using namespace std;
      
      //the function print_2D_matrix receives 4 arguments: pointer to first element
      //                                                   dimension of array arr, i.e. n x m
      //                                                   index of the element to be printed, i.e. a and b
      void print_2D_matrix(int *arr, int n, int m, int a, int b){
          for(int i = 0; i < n; i++){
              for(int j = 0; j < m; j++)
                  printf("%d ", *(arr + (i * m) + j));
              printf("\n");
          }
          //go to the address just before a row, i.e. (a - 1) * NO_OF_COLUMNS 
          //then go to the address on b column, i.e. (a - 1) * NO_OF_COLUMNS + b
          //since we started from the base address, i.e. first element( arr[0][0] ), subtract 1 
          printf("arr[3][3] = %d\n", *(arr + ((a - 1) * m) + b - 1));    //print arr[a][b]
      } 
      
      int main() {
          int n, m;
          cin>>n>>m;
          int arr[n][m];
      
          for(int i = 0; i < n; i++)    //initialize the matrix
              for(int j = 0; j < m; j++)
                  arr[i][j] = i * j;
      
          print_2D_matrix((int *) arr, n, m, 3, 3);
      
          return 0;
      }
      

      上述程序的输出(对于 n x m = 4 x 5)是:

      0 0 0 0 0
      0 1 2 3 4
      0 2 4 6 8
      0 3 6 9 12
      arr[3][3] = 4
      

      【讨论】:

        【解决方案5】:

        我确信这至少违反了 C 标准的一条规则,但它应该在实践中起作用。请注意,它使用 0 作为数组任何级别的终止元素的标记值。

        void print(void* p, int dim)
        {
            if (dim == 1)
            {
                int* a = (int*) p;
                while (*a)
                {
                    printf("%d ", *a++);
                }
                printf("\n");
            }
            else
            {
                void** a = (void**)p;
                while (*a)
                {
                    print(*a++, dim - 1);
                }
            }
        }
        
        void test()
        {
            int x0 [] = { 11, 12, 13, 14, 15, 0 };
            int x1 [] = { 21, 22, 23, 0 };
            int x2 [] = { 0 };
            int x3 [] = { 41, 42, 0 };
            int x4 [] = { 51, 52, 53, 0 };
            int* y0 [] = { x0, x3, 0 };
            int* y1 [] = { 0 };
            int* y2 [] = { x1, x2, x4, 0 };
            int** z [] = { y0, y1, y2, 0 };
        
            print(z, 3);
        }
        

        打印:

        11 12 13 14 15
        41 42
        21 22 23
        
        51 52 53
        

        【讨论】:

        • 投反对票时请发表评论。
        • 您可以添加一些const
        猜你喜欢
        • 2018-11-17
        • 1970-01-01
        • 2016-12-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-16
        • 2016-06-16
        • 1970-01-01
        相关资源
        最近更新 更多