2

我正在编写一个用于矩阵乘法的 C 函数。它需要两个 2D 整数数组。如果我知道输入数组的维度,我可以做到这一点,但我想做一个更通用的函数。

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

4

6 回答 6

5

如果你只有一个指向数组开头的指针,你就无法找出数组的维度。您需要将数组的维度传递给函数。

于 2012-05-04T16:48:56.790 回答
4

这个答案完全是矫枉过正,但这是我struct的基础方法,nm 称之为“一个完整的'另一个故事”。

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

下面的代码显示了一种可能的方法。请注意,这里有几个“技巧”。首先,数据都存储在一个连续的块中——这可能出于多种原因提高性能。这种技术的一个潜在缺点是调整矩阵的大小变得昂贵,因为您必须分配一个全新的实例并复制数据。但是如果你发现这是一个问题,你总是可以改变你的实现,假设你总是使用 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;
}
于 2012-05-04T17:36:22.647 回答
2

你最好为你的数组创建一个 MATRIX 结构。正如@David 所指出的,在 C 中,您必须自己跟踪尺寸。语言中没有内置函数可以安全地为您执行此操作。

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

试试这个:

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)。

祝你好运!

于 2012-05-04T17:19:38.747 回答
2

C 中没有真正的二维数组。只有数组的数组,它们并不完全相同。(我知道我会因为这样说而被殴打。请耐心等待。)

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

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 */

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

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;
};

但那完全是另一回事了。

于 2012-05-04T17:33:02.993 回答
1

您将需要传递数组的维度。然后你将不得不动态分配第三个数组来保存结果。一旦你计算了结果矩阵,你就可以返回一个指向它的指针。

沿着这些线尝试一些东西,其中 A 是一个 nxm 矩阵, B 是一个 mxp 矩阵:

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
}
于 2012-05-04T16:52:10.753 回答
0
#include <stdio.h>

void foo(int *a, int m, int n)
{
    for(int i=0; i<m; i++)
        for(int j=0; j<n; j++)
            printf("%d\n", *(a+i*n+j)); 
}
int main()
{
    int a[][2] = {{1,2},{3,4}};
    foo((int *)a,2,2);
    return 0;
}

通常二维数组以行主要方式存储。二维数组可以被认为是指向元素数组的指针数组。由于我们还传递了两个维度,因此我们可以相应地访问元素。

即使您可以尝试其他数据类型。下面我使用了结构。

#include <stdio.h>
struct abc
{
    int a;
    float b;
    char c;
};
void foo(struct abc *a, int m, int n)
{
    for(int i=0; i<m; i++)
        for(int j=0; j<n; j++)
            printf("%d %f %c\n", (a+i*n+j)->a, (a+i*n+j)->b, (a+i*n+j)->c); 
}
int main()
{
    struct abc a[][2] = {{{1,1.0,'a'},{2,2.0,'b'}}, {{3,3.0,'c'},{4,4.0,'d'}}};
    foo((struct abc *)a,2,2);
    return 0;
}

希望能帮助到你....!!!!!

于 2017-08-11T10:03:52.377 回答