如何使用尺寸未知的2D数组?

时间:2012-05-04 16:46:06

标签: c arrays multidimensional-array matrix-multiplication

我正在为矩阵乘法编写C函数。它需要两个二维2D数组。如果我知道输入数组的大小,我可以这样做,但我想做一个更通用的功能。

如何在编译时不知道产品的尺寸时如何找到它们的尺寸以及如何返回数组?

5 个答案:

答案 0 :(得分:5)

如果只有指向数组开头的指针,则无法找到数组的维数。您需要将数组的维度传递给函数。

答案 1 :(得分:4)

这个答案完全矫枉过正,但这是我基于struct的方法。被称为“整个'其他故事。”

如果这是一个新程序(即你要定义函数的输入/输出是什么样的)并且你打算用矩阵做很多工作,我倾向于用一个结构来表示矩阵,并只传递指向该结构的实例的指针。

下面的代码显示了一种可能的方法。请注意,这里有一些“诡计”。首先,数据全部存储在一个连续的块中 - 由于多种原因,这可能会提高性能。这种技术的一个潜在缺点是调整矩阵的大小变得昂贵,因为你必须分配一个全新的实例并复制数据。但是如果你发现这是一个问题,你总是可以改变你的实现,假设你总是使用matrix_get()和matrix_set()函数来访问矩阵中的值。

此外,矩阵结构和数据指针指向的内存全部在单个malloc调用中分配。如果您使用此技术,请注意数据对齐问题。例如,如果将数据更改为指向64位整数或双精度数,则需要添加填充以确保所有内容都是8字节对齐的。或者,只需将malloc数据指针作为new_matrix()函数中的单独数组,只要您记得在free_matrix()中将其释放。

我作为练习留给OP来编写乘法函数。

#include <stdio.h>
#include <stdlib.h>

struct matrix
{
   int   rows;
   int   cols;
   int * data;
};

struct matrix * new_matrix( int rows, int cols )
{
   struct matrix * m = NULL;

   /* Allocate a block of memory large enough to hold the matrix 'header' struct
    * as well as all the row/column data */
   m = malloc( sizeof(struct matrix)  + (rows * cols * sizeof(int) ) );

   if( m )
   {
      m->rows = rows;
      m->cols = cols;

      /* Some ugly pointer math to get to the first byte of data */
      m->data = (int*) ( (char *) m  + sizeof(*m) );
   }
   return m;
}

void free_matrix( struct matrix * m )
{
   free( m );
}

int matrix_set( struct matrix * m, int row, int col, int val)
{
   if( col >= m->cols || row >= m->rows )
      return -1;
   m->data[ m->cols * row + col ] = val;
   return 0;
}

int matrix_get( struct matrix * m, int row, int col, int * val)
{
   if( col >= m->cols || row >= m->rows )
      return -1;
   else 
   {
      *val = m->data[ m->cols * row + col ];
      return  0;
   }
}

void print_matrix( struct matrix * m )
{
   int r,c;
   int val;
   for( r = 0; r < m->rows; r++ )
   {
      for( c = 0; c < m->cols; c++ )
      {
         matrix_get( m, r, c, &val );
         printf( "%5d%s", val, c + 1 < m->cols ? "," : "" );
      }
      printf("\n");
   }
}

int main (int argc, char **argv)
{
   int r,c;
   struct matrix * m = new_matrix( 5, 5 );

   for(  r = 0; r < m->rows; r++ )
   {
      for( c = 0; c < m->cols; c++ )
      {
         matrix_set( m, r, c, (r +1)* 10 + c + 1 );
      }
   }

   print_matrix( m );
   free_matrix( m );
   return 0;
}

答案 2 :(得分:2)

最好为阵列创建MATRIX结构。正如@David指出的那样,在C中,你必须自己跟踪尺寸。语言中没有内置功能可以安全地为您完成此任务。

strlen()等函数用于字符串(即:以\ 0结尾的char数组),但不包括数组之类的函数。跟踪这一点的最简单方法是创建自己的抽象数据类型和辅助函数。

试试这个:

typedef struct matrix {
  int **array;
  int rows;
  int cols;
} matrix_t;


int createMatrix(matrix_t* mtx) {
  int i;
  if (!mtx) {
    printf("INVALID POINTER TO MATRIX");
    return -1;
  }
  if ( (mtx->rows == 0) || (mtx->cols == 0) ) {
    printf("Rows/columns cannot be zero!");
    return -1;
  }
  int status = 0;
  // allocate the array
  mtx->array = (int **)calloc(mtx->rows,sizeof(int*));
  if(mtx->array != NULL) {
    // memory allocation succeeded
    for(i = 0; i < mtx->rows; i++) {
      if((mtx->array[i] = (int*)calloc(mtx->cols,sizeof(int))) == NULL) {
        printf("Memory allocation error");
        status = -1;
        break;
      } else {
        // Allocation successful
      }
    }
  } else {
    printf("Memory allocation error!");
    status = -1;
  }
  return status;
}

int destroyMatrix(matrix_t* mtx) {
  // destroy the array
  for(i = 0; i < mtx->rows; i++) {
    if(mtx->array[i] != NULL) {
      free(mtx->array[i]);
      mtx->array[i] = NULL;
    }
  }
  if(mtx->array) {
    free(mtx->array);
    mtx->array = NULL;
  }
  return 0;
}

现在您可以创建一个新的矩阵结构,设置其行/列值,调用createMatrix,然后设置:

  matrix_t myMtx;
  myMtx.array = NULL;
  myMtx.rows = 3;
  myMtx.cols = myMtx.cols; // Make it a square matrix
  if(createMatrix(&myMtx) == 0 ) {
    printf("Created matrix successfully");
  } else {
    printf("Failed to create matrix!");
  }

这些函数还可以检查内存分配是否失败,并通过在使用之前检查所有指针来避免程序崩溃(即:SEGFAULT)。

祝你好运!

答案 3 :(得分:2)

C中没有真正的2D数组。只有数组的数组,这些数组并不完全相同。 (我知道我会因为这样说而受到殴打。请耐心等待。)

虽然差异可能看起来不是很显着,但确实如此。要使用数组,您不必在编译时知道它的维度。例如

double dot_product (double a[], double b[], int size); 
/* an A-OK function */

但是必须知道任何数组元素的大小。例如

void matrix_product (double a[][], double b[][], double result[][], 
                     int a_rows, int a_cols, int b_cols);
/* Bad, would not compile. You are only permitted to say "double[N][]", 
   where N is known at compile time */

如果你想要完全通用的矩阵操作代码,你需要使用普通的1D数组,并自己计算行数和列数的索引。你还必须传递尺寸。

void matrix_product (double a[], double b[], double result[], 
                     int a_rows, int a_cols, int b_cols) {
  ...
  for (col = 0; col < a_cols; ++col) {
    for (row = 0; row < a_rows; ++row) {
      ...
      ... a[row*a_cols + col] ...
      ...

在此示例中,调用者分配result,而不是乘法函数。


在某个更高级别,您需要将矩阵与其维度一起封装在某种形式的抽象矩阵数据类型中,如下所示:

struct matrix {
  double* elements;
  int rows, cols;
};

但这是一个完整的'其他故事。

答案 4 :(得分:1)

您需要传递数组的尺寸。然后,您必须动态分配第三个数组来保存结果。计算完结果矩阵后,可以返回指向它的指针。

沿着这些线尝试一些东西,其中A是n×m矩阵,B是m×p矩阵:

int* matix_multiply(int* matrix_a, int* matrix_b, int n, m, int p){

    int *result = (int *) malloc(sizeof(int) * a_rows * b_cols);
    if(result == NULL)
        exit(EXIT_FAILURE);
    //loops to do the actual multiplication and store the results in result[i][j]
    return result; //returns the result array
}